gusucode.com > 各种VC自绘控件源码程序 > 各种VC自绘控件源码/code/SkinControls(自绘MFC基本控件 )/SkinControls/SkinControls/SkinMenu.cpp
#include "stdafx.h" // Standard windows header file #include "SkinMenu.h" // CSkinMenu class declaration #include "MemDC.h" #pragma warning(disable : 4244) #pragma warning(disable : 4312) #pragma warning(disable : 4311) #ifndef ARRAY_SIZE #define ARRAY_SIZE(a) (sizeof(a)/sizeof(a[0])) #endif #ifndef COLOR_MENUBAR #define COLOR_MENUBAR 30 #endif #ifndef SPI_GETDROPSHADOW #define SPI_GETDROPSHADOW 0x1024 #endif #ifndef SPI_GETFLATMENU #define SPI_GETFLATMENU 0x1022 #endif #ifndef ODS_NOACCEL #define ODS_NOACCEL 0x0100 #endif #ifndef DT_HIDEPREFIX #define DT_HIDEPREFIX 0x00100000 #endif #ifndef DT_PREFIXONLY #define DT_PREFIXONLY 0x00200000 #endif #ifndef SPI_GETKEYBOARDCUES #define SPI_GETKEYBOARDCUES 0x100A #endif #define MENU_ROUND_CX 5 #define MENU_ROUND_CY 5 // Count of menu icons normal gloomed and grayed #define MENU_ICONS 3 BOOL bHighContrast = FALSE; ///////////////////////////////////////////////////////////////////////////// // Helper datatypes class CToolBarData { public: WORD wVersion; WORD wWidth; WORD wHeight; WORD wItemCount; //WORD aItems[wItemCount] WORD* items() { return (WORD*)(this+1); } }; class CSkinMenuIconInfo { public: WORD wBitmapID; WORD wWidth; WORD wHeight; WORD* ids(){ return (WORD*)(this+1); } }; #ifdef _DEBUG static void ShowLastError(LPCTSTR pErrorTitle=NULL) { if(pErrorTitle==NULL) { pErrorTitle=_T("Error from Menu"); } DWORD error = GetLastError(); if(error) { LPVOID lpMsgBuf=NULL; FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, error, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language (LPTSTR) &lpMsgBuf, 0, NULL ); if(lpMsgBuf) { // Display the string. MessageBox( NULL, (LPCTSTR)lpMsgBuf, pErrorTitle, MB_OK | MB_ICONINFORMATION ); // Free the buffer. LocalFree( lpMsgBuf ); } else { CString temp; temp.Format(_T("Error message 0x%lx not found"),error); // Display the string. MessageBox( NULL,temp, pErrorTitle, MB_OK | MB_ICONINFORMATION ); } } } #else #define ShowLastError(sz) #endif WORD NumBitmapColors(LPBITMAPINFOHEADER lpBitmap) { if ( lpBitmap->biClrUsed != 0) return (WORD)lpBitmap->biClrUsed; switch (lpBitmap->biBitCount) { case 1: return 2; case 4: return 16; case 8: return 256; } return 0; } int NumScreenColors() { static int nColors = 0; if (!nColors) { // DC of the desktop CClientDC myDC(NULL); nColors = myDC.GetDeviceCaps(NUMCOLORS); if (nColors == -1) { nColors = 64000; } } return nColors; } HBITMAP LoadColorBitmap(LPCTSTR lpszResourceName, HMODULE hInst, int* pNumcol) { if(hInst==0) { hInst = AfxFindResourceHandle(lpszResourceName, RT_BITMAP); } HRSRC hRsrc = ::FindResource(hInst,MAKEINTRESOURCE(lpszResourceName),RT_BITMAP); if (hRsrc == NULL) return NULL; // determine how many colors in the bitmap HGLOBAL hglb; if ((hglb = LoadResource(hInst, hRsrc)) == NULL) return NULL; LPBITMAPINFOHEADER lpBitmap = (LPBITMAPINFOHEADER)LockResource(hglb); if (lpBitmap == NULL) return NULL; WORD numcol = NumBitmapColors(lpBitmap); if(pNumcol) { *pNumcol = numcol; } UnlockResource(hglb); FreeResource(hglb); return LoadBitmap(hInst,lpszResourceName); } COLORREF MakeGrayAlphablend(CBitmap* pBitmap, int weighting, COLORREF blendcolor) { CDC myDC; // Create a compatible bitmap to the screen myDC.CreateCompatibleDC(0); // Select the bitmap into the DC CBitmap* pOldBitmap = myDC.SelectObject(pBitmap); BITMAP myInfo = {0}; GetObject((HGDIOBJ)pBitmap->m_hObject,sizeof(myInfo),&myInfo); for (int nHIndex = 0; nHIndex < myInfo.bmHeight; nHIndex++) { for (int nWIndex = 0; nWIndex < myInfo.bmWidth; nWIndex++) { COLORREF ref = myDC.GetPixel(nWIndex,nHIndex); // make it gray DWORD nAvg = (GetRValue(ref) + GetGValue(ref) + GetBValue(ref))/3; // Algorithme for alphablending //dest' = ((weighting * source) + ((255-weighting) * dest)) / 256 DWORD refR = ((weighting * nAvg) + ((255-weighting) * GetRValue(blendcolor))) / 256; DWORD refG = ((weighting * nAvg) + ((255-weighting) * GetGValue(blendcolor))) / 256; DWORD refB = ((weighting * nAvg) + ((255-weighting) * GetBValue(blendcolor))) / 256; myDC.SetPixel(nWIndex,nHIndex,RGB(refR,refG,refB)); } } COLORREF topLeftColor = myDC.GetPixel(0,0); myDC.SelectObject(pOldBitmap); return topLeftColor; } void MenuDrawText(HDC hDC ,LPCTSTR lpString,int nCount,LPRECT lpRect,UINT uFormat) { if(nCount==-1) { nCount = lpString?(int)_tcslen(lpString):0; } LOGFONT logfont = {0}; if(!GetObject(GetCurrentObject(hDC, OBJ_FONT),sizeof(logfont),&logfont)) { logfont.lfOrientation = 0; } size_t bufSizeTChar = nCount + 1; TCHAR* pBuffer = (TCHAR*)_alloca(bufSizeTChar*sizeof(TCHAR)); _tcsncpy_s(pBuffer,bufSizeTChar,lpString,nCount); pBuffer[nCount] = 0; UINT oldAlign = GetTextAlign(hDC); const int nBorder=4; HGDIOBJ hOldFont = NULL; CFont TempFont; TEXTMETRIC textMetric; if (!GetTextMetrics(hDC, &textMetric)) { textMetric.tmOverhang = 0; textMetric.tmAscent = 0; } else if ((textMetric.tmPitchAndFamily&(TMPF_VECTOR|TMPF_TRUETYPE))==0 ) { // we have a bitmapfont it is not possible to rotate if(logfont.lfOrientation || logfont.lfEscapement) { hOldFont = GetCurrentObject(hDC,OBJ_FONT); _tcscpy_s(logfont.lfFaceName,ARRAY_SIZE(logfont.lfFaceName),_T("Arial")); // we need a truetype font for rotation logfont.lfOutPrecision = OUT_TT_ONLY_PRECIS; // the font will be destroyed at the end by destructor TempFont.CreateFontIndirect(&logfont); // we select at the end the old font SelectObject(hDC,TempFont); GetTextMetrics(hDC, &textMetric); } } DWORD dwLayout = GetLayout(hDC); if(dwLayout&LAYOUT_RTL) { SetTextAlign (hDC,TA_RIGHT|TA_TOP|TA_UPDATECP); } else { SetTextAlign (hDC,TA_LEFT|TA_TOP|TA_UPDATECP); } CPoint pos(lpRect->left,lpRect->top); if( (uFormat&DT_VCENTER) &&lpRect) { switch(logfont.lfOrientation%3600) { default: case 0: logfont.lfOrientation = 0; pos.y = (lpRect->top+lpRect->bottom-textMetric.tmHeight)/2; if(dwLayout&LAYOUT_RTL) { pos.x = lpRect->right - nBorder; } else { pos.x = lpRect->left + nBorder; } break; case 1800: case -1800: logfont.lfOrientation = 1800; pos.y = (lpRect->top+textMetric.tmHeight +lpRect->bottom)/2; if(dwLayout&LAYOUT_RTL) { pos.x = lpRect->left + nBorder; } else { pos.x = lpRect->right - nBorder; } break; case 900: case -2700: logfont.lfOrientation = 900; pos.x = (lpRect->left+lpRect->right-textMetric.tmHeight)/2; pos.y = lpRect->bottom - nBorder; if(dwLayout&LAYOUT_RTL) { pos.y = lpRect->top + nBorder; } else { pos.y = lpRect->bottom - nBorder; } break; case -900: case 2700: logfont.lfOrientation = 2700; pos.x = (lpRect->left+lpRect->right+textMetric.tmHeight)/2; if(dwLayout&LAYOUT_RTL) { pos.y = lpRect->bottom - nBorder; } else { pos.y = lpRect->top + nBorder; } break; } } CPoint oldPos; MoveToEx(hDC,pos.x,pos.y,&oldPos); while(nCount) { TCHAR *pTemp =_tcsstr(pBuffer,_T("&")); if(pTemp) { // we found & if(*(pTemp+1)==_T('&')) { // the different is in character unicode and byte works int nTempCount = DWORD(pTemp-pBuffer)+1; ExtTextOut(hDC,pos.x,pos.y,ETO_CLIPPED,lpRect,pBuffer,nTempCount,NULL); nCount -= nTempCount+1; pBuffer = pTemp+2; } else { // draw underline the different is in character unicode and byte works int nTempCount = DWORD(pTemp-pBuffer); ExtTextOut(hDC,pos.x,pos.y,ETO_CLIPPED,lpRect,pBuffer,nTempCount,NULL); nCount -= nTempCount+1; pBuffer = pTemp+1; if(!(uFormat&DT_HIDEPREFIX) ) { CSize size; GetTextExtentPoint(hDC, pTemp+1, 1, &size); GetCurrentPositionEx(hDC,&pos); COLORREF oldColor = SetBkColor(hDC, GetTextColor(hDC)); LONG cx = size.cx - textMetric.tmOverhang / 2; LONG nTop; CRect rc; switch(logfont.lfOrientation) { case 0: // Get height of text so that underline is at bottom. nTop = pos.y + textMetric.tmAscent + 1; // Draw the underline using the foreground color. if(dwLayout&LAYOUT_RTL) { rc.SetRect(pos.x-cx+2, nTop, pos.x+1, nTop+1); } else { rc.SetRect(pos.x, nTop, pos.x+cx, nTop+1); } ExtTextOut(hDC, pos.x, nTop, ETO_OPAQUE, &rc, _T(""), 0, NULL); break; case 1800: // Get height of text so that underline is at bottom. nTop = pos.y -(textMetric.tmAscent + 1); // Draw the underline using the foreground color. if(dwLayout&LAYOUT_RTL) { rc.SetRect(pos.x-1, nTop-1, pos.x+cx-1, nTop); } else { rc.SetRect(pos.x-cx, nTop-1, pos.x, nTop); } ExtTextOut(hDC, pos.x, nTop, ETO_OPAQUE, &rc, _T(""), 0, NULL); break; case 900: // draw up // Get height of text so that underline is at bottom. nTop = pos.x + (textMetric.tmAscent + 1); // Draw the underline using the foreground color. if(dwLayout&LAYOUT_RTL) { rc.SetRect(nTop-1, pos.y, nTop, pos.y+cx-2); } else { rc.SetRect(nTop, pos.y-cx, nTop+1, pos.y); } ExtTextOut(hDC, nTop, pos.y, ETO_OPAQUE, &rc, _T(""), 0, NULL); break; case 2700: // draw down // Get height of text so that underline is at bottom. nTop = pos.x -(textMetric.tmAscent + 1); // Draw the underline using the foreground color. if(dwLayout&LAYOUT_RTL) { rc.SetRect(nTop, pos.y-cx+1 , nTop+1, pos.y); } else { rc.SetRect(nTop-1, pos.y, nTop, pos.y+cx); } ExtTextOut(hDC, nTop, pos.y, ETO_OPAQUE, &rc, _T(""), 0, NULL); break; } SetBkColor(hDC, oldColor); // corect the actual drawingpoint MoveToEx(hDC,pos.x,pos.y,NULL); } } } else { // draw the rest of the string ExtTextOut(hDC,pos.x,pos.y,ETO_CLIPPED,lpRect,pBuffer,nCount,NULL); break; } } // restore old point MoveToEx(hDC,oldPos.x,oldPos.y,NULL); // restore old align SetTextAlign(hDC,oldAlign); if(hOldFont!=NULL) { SelectObject(hDC,hOldFont); } } Win32Type IsShellType() { OSVERSIONINFO osvi = {0}; osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); DWORD winVer=GetVersion(); if(winVer<0x80000000) {/*NT */ if(!GetVersionEx(&osvi)) { ShowLastError(_T("Error from Menu: GetVersionEx NT")); } if(osvi.dwMajorVersion==4L) { return WinNT4; } else if(osvi.dwMajorVersion==5L && osvi.dwMinorVersion==0L) { return Win2000; } // thanks to John Zegers else if(osvi.dwMajorVersion>=5L)// && osvi.dwMinorVersion==1L) { return WinXP; } return WinNT3; } else if (LOBYTE(LOWORD(winVer))<4) { return Win32s; } if(!GetVersionEx(&osvi)) { ShowLastError(_T("Error from Menu: GetVersionEx")); } if(osvi.dwMajorVersion==4L && osvi.dwMinorVersion==10L) { return Win98; } else if(osvi.dwMajorVersion==4L && osvi.dwMinorVersion==90L) { return WinME; } return Win95; } BOOL IsShadowEnabled() { BOOL bEnabled = FALSE; if(SystemParametersInfo(SPI_GETDROPSHADOW,0,&bEnabled,0)) { return bEnabled; } return FALSE; } COLORREF DarkenColorXP(COLORREF color) { return RGB( MulDiv(GetRValue(color),7,10), MulDiv(GetGValue(color),7,10), MulDiv(GetBValue(color)+55,7,10)); } // Function splits a color into its RGB components and // transforms the color using a scale 0..255 COLORREF DarkenColor( long lScale, COLORREF lColor) { long red = MulDiv(GetRValue(lColor),(255-lScale),255); long green = MulDiv(GetGValue(lColor),(255-lScale),255); long blue = MulDiv(GetBValue(lColor),(255-lScale),255); return RGB(red, green, blue); } COLORREF MixedColor(COLORREF colorA,COLORREF colorB) { // ( 86a + 14b ) / 100 int red = MulDiv(86,GetRValue(colorA),100) + MulDiv(14,GetRValue(colorB),100); int green = MulDiv(86,GetGValue(colorA),100) + MulDiv(14,GetGValue(colorB),100); int blue = MulDiv(86,GetBValue(colorA),100) + MulDiv(14,GetBValue(colorB),100); return RGB( min(red,0xff),min(green,0xff), min(blue,0xff)); } COLORREF MidColor(COLORREF colorA,COLORREF colorB) { // (7a + 3b)/10 int red = MulDiv(7,GetRValue(colorA),10) + MulDiv(3,GetRValue(colorB),10); int green = MulDiv(7,GetGValue(colorA),10) + MulDiv(3,GetGValue(colorB),10); int blue = MulDiv(7,GetBValue(colorA),10) + MulDiv(3,GetBValue(colorB),10); return RGB( min(red,0xff),min(green,0xff), min(blue,0xff)); } COLORREF GrayColor(COLORREF crColor) { int Gray = (((int)GetRValue(crColor)) + GetGValue(crColor) + GetBValue(crColor))/3; return RGB( Gray,Gray,Gray); } BOOL IsLightColor(COLORREF crColor) { return (((int)GetRValue(crColor)) + GetGValue(crColor) + GetBValue(crColor))>(3*128); } COLORREF GetXpHighlightColor() { if(bHighContrast) { return GetSysColor(COLOR_HIGHLIGHT); } if (NumScreenColors() > 256) { // May-05-2005 - Mark P. Peterson (mpp@rhinosoft.com) - Changed to use "MixedColor1()" instead when not using XP Theme mode. // It appears that using MidColor() in many non XP Themes cases returns the wrong color, this needs to be much more like the // highlight color as the user has selected in Windows. If the highlight color is YELLOW, for example, and the COLOR_WINDOW // value is WHITE, using MidColor() the function returns a dark blue color making the menus too hard to read. if (IsLightColor(GetSysColor(COLOR_HIGHLIGHT))) return MixedColor(GetSysColor(COLOR_WINDOW),GetSysColor(COLOR_HIGHLIGHT)); else return MidColor(GetSysColor(COLOR_WINDOW),GetSysColor(COLOR_HIGHLIGHT)); // as released by Bruno // return MidColor(GetSysColor(COLOR_WINDOW),GetSysColor(COLOR_HIGHLIGHT)); } return GetSysColor(COLOR_WINDOW); } // Function splits a color into its RGB components and // transforms the color using a scale 0..255 COLORREF LightenColor( long lScale, COLORREF lColor) { long R = MulDiv(255-GetRValue(lColor),lScale,255)+GetRValue(lColor); long G = MulDiv(255-GetGValue(lColor),lScale,255)+GetGValue(lColor); long B = MulDiv(255-GetBValue(lColor),lScale,255)+GetBValue(lColor); return RGB(R, G, B); } COLORREF BleachColor(int Add, COLORREF color) { return RGB( min (GetRValue(color)+Add, 255), min (GetGValue(color)+Add, 255), min (GetBValue(color)+Add, 255)); } COLORREF GetAlphaBlendColor(COLORREF blendColor, COLORREF pixelColor,int weighting) { if(pixelColor==CLR_NONE) { return CLR_NONE; } // Algorithme for alphablending //dest' = ((weighting * source) + ((255-weighting) * dest)) / 256 DWORD refR = ((weighting * GetRValue(pixelColor)) + ((255-weighting) * GetRValue(blendColor))) / 256; DWORD refG = ((weighting * GetGValue(pixelColor)) + ((255-weighting) * GetGValue(blendColor))) / 256; DWORD refB = ((weighting * GetBValue(pixelColor)) + ((255-weighting) * GetBValue(blendColor))) / 256; return RGB(refR,refG,refB); } void DrawGradient1(CDC* pDC,CRect& Rect, COLORREF StartColor,COLORREF EndColor, BOOL bHorizontal,BOOL bUseSolid) { int Count = pDC->GetDeviceCaps(NUMCOLORS); if(Count==-1) bUseSolid = FALSE; // for running under win95 and WinNt 4.0 without loading Msimg32.dll if(!bUseSolid ) { TRIVERTEX vert[2]; GRADIENT_RECT gRect; vert [0].y = Rect.top; vert [0].x = Rect.left; vert [0].Red = COLOR16(COLOR16(GetRValue(StartColor))<<8); vert [0].Green = COLOR16(COLOR16(GetGValue(StartColor))<<8); vert [0].Blue = COLOR16(COLOR16(GetBValue(StartColor))<<8); vert [0].Alpha = 0x0000; vert [1].y = Rect.bottom; vert [1].x = Rect.right; vert [1].Red = COLOR16(COLOR16(GetRValue(EndColor))<<8); vert [1].Green = COLOR16(COLOR16(GetGValue(EndColor))<<8); vert [1].Blue = COLOR16(COLOR16(GetBValue(EndColor))<<8); vert [1].Alpha = 0x0000; gRect.UpperLeft = 0; gRect.LowerRight = 1; if(bHorizontal) { GradientFill(pDC->m_hDC,vert,2,&gRect,1,GRADIENT_FILL_RECT_H); } else { GradientFill(pDC->m_hDC,vert,2,&gRect,1,GRADIENT_FILL_RECT_V); } } else { BYTE StartRed = GetRValue(StartColor); BYTE StartGreen = GetGValue(StartColor); BYTE StartBlue = GetBValue(StartColor); BYTE EndRed = GetRValue(EndColor); BYTE EndGreen = GetGValue(EndColor); BYTE EndBlue = GetBValue(EndColor); int n = (bHorizontal)?Rect.Width():Rect.Height(); // only need for the rest, can be optimized { if(bUseSolid) { // We need a solid brush (can not be doted) pDC->FillSolidRect(Rect,pDC->GetNearestColor(EndColor)); } else { // We need a brush (can be doted) CBrush TempBrush(EndColor); pDC->FillRect(Rect,&TempBrush); } } int dy = 2; n-=dy; for(int dn=0;dn<=n;dn+=dy) { BYTE ActRed = (BYTE)(MulDiv(int(EndRed) -StartRed, dn,n)+StartRed); BYTE ActGreen = (BYTE)(MulDiv(int(EndGreen)-StartGreen,dn,n)+StartGreen); BYTE ActBlue = (BYTE)(MulDiv(int(EndBlue) -StartBlue, dn,n)+StartBlue); CRect TempRect; if(bHorizontal) { TempRect = CRect(CPoint(Rect.left+dn,Rect.top),CSize(dy,Rect.Height())); } else { TempRect = CRect(CPoint(Rect.left,Rect.top+dn),CSize(Rect.Width(),dy)); } if(bUseSolid) { pDC->FillSolidRect(TempRect,pDC->GetNearestColor(RGB(ActRed,ActGreen,ActBlue))); } else { CBrush TempBrush(RGB(ActRed,ActGreen,ActBlue)); pDC->FillRect(TempRect,&TempBrush); } } } } //void DrawGradient2(CDC* pDC,CRect& Rect, COLORREF Color1,COLORREF Color2, COLORREF Color3, BOOL bHorizontal) //{ // TRIVERTEX vert[4]; // GRADIENT_RECT gRect[2]; // // vert [0].y = Rect.top; // vert [0].x = Rect.left; // vert [0].Red = COLOR16(COLOR16(GetRValue(Color1))<<8); // vert [0].Green = COLOR16(COLOR16(GetGValue(Color1))<<8); // vert [0].Blue = COLOR16(COLOR16(GetBValue(Color1))<<8); // vert [0].Alpha = 0x0000; // // vert [1].y = Rect.bottom; // vert [1].x = Rect.right / 2; // vert [1].Red = COLOR16(COLOR16(GetRValue(Color2))<<8); // vert [1].Green = COLOR16(COLOR16(GetGValue(Color2))<<8); // vert [1].Blue = COLOR16(COLOR16(GetBValue(Color2))<<8); // vert [1].Alpha = 0x0000; // // vert [2].y = Rect.top; // vert [2].x = Rect.right / 2; // vert [2].Red = COLOR16(COLOR16(GetRValue(Color2))<<8); // vert [2].Green = COLOR16(COLOR16(GetGValue(Color2))<<8); // vert [2].Blue = COLOR16(COLOR16(GetBValue(Color2))<<8); // vert [2].Alpha = 0x0000; // // vert [3].y = Rect.bottom; // vert [3].x = Rect.right; // vert [3].Red = COLOR16(COLOR16(GetRValue(Color3))<<8); // vert [3].Green = COLOR16(COLOR16(GetGValue(Color3))<<8); // vert [3].Blue = COLOR16(COLOR16(GetBValue(Color3))<<8); // vert [3].Alpha = 0x0000; // // gRect[0].UpperLeft = 0; // gRect[0].LowerRight = 1; // // gRect[1].UpperLeft = 2; // gRect[1].LowerRight = 3; // // if(bHorizontal) // { // GradientFill(pDC->m_hDC,vert,2,&gRect,2,GRADIENT_FILL_RECT_H); // } // else // { // GradientFill(pDC->m_hDC,vert,2,&gRect,2,GRADIENT_FILL_RECT_V); // } //} ///////////////////////////////////////////////////////////////////////////// // CSkinMenuHook important class for subclassing menus! class CSkinMenuHook { public: class CMenuHookData { public: CMenuHookData(HWND hWnd,BOOL bSpecialWnd) : m_dwData(bSpecialWnd),m_bDrawBorder(TRUE),m_Point(0,0), m_hRgn((HRGN)1),m_bDoSubclass(TRUE) //, m_hRightShade(NULL),m_hBottomShade(NULL),m_TimerID(0) { // Safe actual menu SetMenu(CSkinMenuHook::m_hLastMenu); // Reset for the next menu CSkinMenuHook::m_hLastMenu = NULL; // Save actual border setting etc. m_dwStyle = GetWindowLongPtr(hWnd, GWL_STYLE); m_dwExStyle = GetWindowLongPtr(hWnd, GWL_EXSTYLE); //if(pSetWindowTheme)pSetWindowTheme(hWnd,L" ",L" "); } ~CMenuHookData() { if(m_hRgn!=(HRGN)1) { DeleteObject(m_hRgn); m_hRgn = (HRGN)1; } } BOOL SetMenu(HMENU hMenu) { m_hMenu = hMenu; if(!CSkinMenu::GetNewMenuBorderAllMenu() && !DYNAMIC_DOWNCAST(CSkinMenu,CMenu::FromHandlePermanent(hMenu))) { m_bDoSubclass = FALSE; } else { m_bDoSubclass = TRUE; } return m_bDoSubclass; } LONG_PTR m_dwStyle; LONG_PTR m_dwExStyle; CPoint m_Point; DWORD m_dwData; // 1=Sepcial WND, 2=Styles Changed,4=VK_ESCAPE, 8=in Print BOOL m_bDrawBorder; HMENU m_hMenu; CBitmap m_Screen; HRGN m_hRgn; BOOL m_bDoSubclass; }; public: CSkinMenuHook(); ~CSkinMenuHook(); public: static CMenuHookData* GetMenuHookData(HWND hWnd); private: static LRESULT CALLBACK SkinMenuHook(int code, WPARAM wParam, LPARAM lParam); static BOOL CheckSubclassing(HWND hWnd,BOOL bSpecialWnd); static LRESULT CALLBACK SubClassMenu(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam ); static void UnsubClassMenu(HWND hWnd); static BOOL SubClassMenu2(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, DWORD* pResult); public: static HMENU m_hLastMenu; static DWORD m_dwMsgPos; static DWORD m_bSubclassFlag; private: //static HMODULE m_hThemeLibrary; static HHOOK HookOldMenuCbtFilter; // an map of actual opened Menu and submenu static CTypedPtrMap<CMapPtrToPtr,HWND,CMenuHookData*> m_MenuHookData; }; ///////////////////////////////////////////////////////////////////////////// // CSkinMenuIconLock Helperclass for reference-counting ! class CSkinMenuIconLock { CSkinMenuIcons* m_pIcons; public: CSkinMenuIconLock(CSkinMenuIcons* pIcons):m_pIcons(pIcons) { m_pIcons->AddRef(); } ~CSkinMenuIconLock() { m_pIcons->Release(); } operator CSkinMenuIcons*(){return m_pIcons;} }; ////////////////////////////////////////////////////////////////////// // Construction/Destruction ////////////////////////////////////////////////////////////////////// IMPLEMENT_DYNAMIC(CSkinMenuIcons,CObject); CSkinMenuIcons::CSkinMenuIcons() : m_lpszResourceName(NULL), m_hInst(NULL), m_hBitmap(NULL), m_nColors(0), m_crTransparent(CLR_NONE), m_dwRefCount(0) { } CSkinMenuIcons::~CSkinMenuIcons() { if(m_lpszResourceName && !IS_INTRESOURCE(m_lpszResourceName)) { delete (LPTSTR)m_lpszResourceName; } } int CSkinMenuIcons::AddRef() { if(this==NULL) return NULL; return ++m_dwRefCount; } int CSkinMenuIcons::Release() { if(this==NULL) return NULL; DWORD dwCount = --m_dwRefCount; if(m_dwRefCount==0) { if(CSkinMenu::m_pSharedMenuIcons) { POSITION pos = CSkinMenu::m_pSharedMenuIcons->Find(this); if(pos) { CSkinMenu::m_pSharedMenuIcons->RemoveAt(pos); } } delete this; } return dwCount; } #if defined(_DEBUG) || defined(_AFXDLL) // Diagnostic Support void CSkinMenuIcons::AssertValid() const { CObject::AssertValid(); } void CSkinMenuIcons::Dump(CDumpContext& dc) const { CObject::Dump(dc); dc << _T("NewMenuIcons: ") << _T("\n"); } #endif BOOL CSkinMenuIcons::DoMatch(LPCTSTR lpszResourceName, HMODULE hInst) { if(hInst==m_hInst && lpszResourceName) { if(IS_INTRESOURCE(m_lpszResourceName)) { return (lpszResourceName==m_lpszResourceName); } return (_tcscmp(lpszResourceName,m_lpszResourceName)==0); } return FALSE; } BOOL CSkinMenuIcons::DoMatch(HBITMAP hBitmap, CSize size, UINT* pID) { if(pID && m_hBitmap==hBitmap) { CSize iconSize = GetIconSize(); if(iconSize==size) { int nCount = (int)m_IDs.GetSize(); for(int nIndex=0 ; nIndex<nCount ; nIndex++,pID++) { if( (*pID)==0 || m_IDs.GetAt(nIndex)!=(*pID) ) { return FALSE; } } return TRUE; } } return FALSE; } BOOL CSkinMenuIcons::DoMatch(WORD* pIconInfo, COLORREF crTransparent) { if(m_crTransparent==crTransparent && pIconInfo!=NULL) { CSkinMenuIconInfo* pInfo = (CSkinMenuIconInfo*)pIconInfo; // Check for the same resource ID if( pInfo->wBitmapID && IS_INTRESOURCE(m_lpszResourceName) && ((UINT)(UINT_PTR)m_lpszResourceName)==pInfo->wBitmapID) { int nCount = (int)m_IDs.GetSize(); WORD* pID = pInfo->ids(); for(int nIndex=0 ; nIndex<nCount ; nIndex++,pID++) { if( (*pID)==0 || m_IDs.GetAt(nIndex)!=(*pID) ) { return FALSE; } } return TRUE; } } return FALSE; } int CSkinMenuIcons::FindIndex(UINT nID) { int nIndex = (int)m_IDs.GetSize(); while(nIndex--) { if(m_IDs.GetAt(nIndex)==nID) { return nIndex*MENU_ICONS; } } return -1; } BOOL CSkinMenuIcons::GetIconSize(int* cx, int* cy) { return ::ImageList_GetIconSize(m_IconsList,cx,cy); } CSize CSkinMenuIcons::GetIconSize() { int cx=0; int cy=0; if(::ImageList_GetIconSize(m_IconsList,&cx,&cy)) { return CSize(cx,cy); } return CSize(0,0); } void CSkinMenuIcons::OnSysColorChange() { if(m_lpszResourceName!=NULL) { int cx=16,cy=16; if(GetIconSize(&cx, &cy) && LoadBitmap(cx,cy,m_lpszResourceName,m_hInst)) { MakeImages(); } } } BOOL CSkinMenuIcons::LoadBitmap(int nWidth, int nHeight, LPCTSTR lpszResourceName, HMODULE hInst) { m_nColors = 0; HBITMAP hBitmap = LoadColorBitmap(lpszResourceName,hInst,&m_nColors); if(hBitmap!=NULL) { CBitmap bitmap; bitmap.Attach(hBitmap); if(m_IconsList.GetSafeHandle()) { m_IconsList.DeleteImageList(); } m_IconsList.Create(nWidth,nHeight,ILC_COLORDDB|ILC_MASK,0,10); m_IconsList.Add(&bitmap,m_crTransparent); return TRUE; } return FALSE; } BOOL CSkinMenuIcons::LoadToolBar(HBITMAP hBitmap, CSize size, UINT* pID, COLORREF crTransparent) { BOOL bResult = FALSE; m_nColors = 0; if(hBitmap!=NULL) { BITMAP myInfo = {0}; if(GetObject(hBitmap,sizeof(myInfo),&myInfo)) { m_crTransparent = crTransparent; if(m_IconsList.GetSafeHandle()) { m_IconsList.DeleteImageList(); } m_IconsList.Create(size.cx,size.cy,ILC_COLORDDB|ILC_MASK,0,10); // Changed by Mehdy Bohlool(zy) ( December_28_2003 ) // // CImageList::Add function change the background color ( color // specified as transparent ) to black, and this bitmap may use // after call to this function, It seem that Load functions do // not change their source data provider ( currently hBitmap ). // Old Code: // CBitmap* pBitmap = CBitmap::FromHandle(hBitmap); // m_IconsList.Add(pBitmap,m_crTransparent); // New Code: { HBITMAP hBitmapCopy; hBitmapCopy = (HBITMAP) CopyImage( hBitmap, IMAGE_BITMAP, 0,0,0); CBitmap* pBitmap = CBitmap::FromHandle(hBitmapCopy); m_IconsList.Add(pBitmap,m_crTransparent); DeleteObject( hBitmapCopy ); } while(*pID) { UINT nID = *(pID++); m_IDs.Add(nID); bResult = TRUE; } MakeImages(); } } return bResult; } BOOL CSkinMenuIcons::LoadToolBar(WORD* pIconInfo, COLORREF crTransparent) { BOOL bResult = FALSE; m_crTransparent = crTransparent; CSkinMenuIconInfo* pInfo = (CSkinMenuIconInfo*)pIconInfo; if (LoadBitmap(pInfo->wWidth,pInfo->wHeight,MAKEINTRESOURCE(pInfo->wBitmapID))) { SetResourceName(MAKEINTRESOURCE(pInfo->wBitmapID)); WORD* pID = pInfo->ids(); while(*pID) { UINT nID = *(pID++); m_IDs.Add(nID); bResult = TRUE; } MakeImages(); } return bResult; } void CSkinMenuIcons::SetResourceName(LPCTSTR lpszResourceName) { ASSERT_VALID(this); ASSERT(lpszResourceName != NULL); if(m_lpszResourceName && !IS_INTRESOURCE(m_lpszResourceName)) { delete [](LPTSTR)m_lpszResourceName; } if( lpszResourceName && !IS_INTRESOURCE(lpszResourceName)) { size_t bufSizeTchar = _tcslen(lpszResourceName)+1; m_lpszResourceName = new TCHAR[bufSizeTchar]; _tcscpy_s((LPTSTR)m_lpszResourceName,bufSizeTchar,lpszResourceName); } else { m_lpszResourceName = lpszResourceName; } } BOOL CSkinMenuIcons::LoadToolBar(LPCTSTR lpszResourceName, HMODULE hInst) { ASSERT_VALID(this); SetResourceName(lpszResourceName); m_hInst = hInst; // determine location of the bitmap in resource if(hInst==0) { hInst = AfxFindResourceHandle(lpszResourceName, RT_TOOLBAR); } HRSRC hRsrc = ::FindResource(hInst, lpszResourceName, RT_TOOLBAR); if (hRsrc == NULL) { // Special purpose when you try to load it from a dll 30.05.2002 if(AfxGetResourceHandle()!=hInst) { hInst = AfxGetResourceHandle(); hRsrc = ::FindResource(hInst, lpszResourceName, RT_TOOLBAR); } if (hRsrc == NULL) { return FALSE; } } HGLOBAL hGlobal = LoadResource(hInst, hRsrc); if (hGlobal == NULL) { return FALSE; } CToolBarData* pData = (CToolBarData*)LockResource(hGlobal); if (pData == NULL) { return FALSE; } BOOL bResult = FALSE; ASSERT(pData->wVersion == 1); if(LoadBitmap(pData->wWidth,pData->wHeight,lpszResourceName,hInst)) { // Remove all previous ID's m_IDs.RemoveAll(); for (int i = 0; i < pData->wItemCount; i++) { UINT nID = pData->items()[i]; if (nID) { m_IDs.Add(nID); bResult = TRUE; } } } UnlockResource(hGlobal); FreeResource(hGlobal); MakeImages(); return bResult; } int CSkinMenuIcons::AddGloomIcon(HICON hIcon, int nIndex) { ICONINFO iconInfo = {0}; if(!GetIconInfo(hIcon,&iconInfo)) { return -1; } CSize size = GetIconSize(); CDC myDC; myDC.CreateCompatibleDC(0); CBitmap bmColor; bmColor.Attach(iconInfo.hbmColor); CBitmap bmMask; bmMask.Attach(iconInfo.hbmMask); CBitmap* pOldBitmap = myDC.SelectObject(&bmColor); COLORREF crPixel; for(int i=0;i<size.cx;++i) { for(int j=0;j<size.cy;++j) { crPixel = myDC.GetPixel(i,j); // Jan-12-2005 - Mark P. Peterson - mpp@rhinosoft.com - http://www.RhinoSoft.com/ // added so the gloom value can be adjusted, this was 50 myDC.SetPixel(i,j,DarkenColor(CSkinMenu::GetGloomFactor(), crPixel)); } } myDC.SelectObject(pOldBitmap); if(nIndex==-1) { return m_IconsList.Add(&bmColor,&bmMask); } return (m_IconsList.Replace(nIndex,&bmColor,&bmMask)) ? nIndex: -1; } int CSkinMenuIcons::AddGrayIcon(HICON hIcon, int nIndex) { ICONINFO iconInfo = {0}; if(!GetIconInfo(hIcon,&iconInfo)) { return -1; } CBitmap bmColor; bmColor.Attach(iconInfo.hbmColor); CBitmap bmMask; bmMask.Attach(iconInfo.hbmMask); COLORREF blendcolor = LightenColor(115,CSkinMenu::GetMenuBarColorXP()); MakeGrayAlphablend(&bmColor,110, blendcolor); if(nIndex==-1) { return m_IconsList.Add(&bmColor,&bmMask); } return (m_IconsList.Replace(nIndex,&bmColor,&bmMask)) ? nIndex: -1; } BOOL CSkinMenuIcons::MakeImages() { int nCount = m_IconsList.GetImageCount(); if(!nCount) { return FALSE; } CSize size = GetIconSize(); CImageList ilTemp; ilTemp.Attach(m_IconsList.Detach()); m_IconsList.Create(size.cx,size.cy,ILC_COLORDDB|ILC_MASK,0,10); for(int nIndex=0;nIndex<nCount;nIndex++) { HICON hIcon = ilTemp.ExtractIcon(nIndex); m_IconsList.Add(hIcon); AddGloomIcon(hIcon); AddGrayIcon(hIcon); DestroyIcon(hIcon); } return TRUE; } ////////////////////////////////////////////////////////////////////// // Construction/Destruction ////////////////////////////////////////////////////////////////////// IMPLEMENT_DYNAMIC(CSkinMenuBitmaps,CSkinMenuIcons); CSkinMenuBitmaps::CSkinMenuBitmaps() { } CSkinMenuBitmaps::~CSkinMenuBitmaps() { } int CSkinMenuBitmaps::Add(UINT nID, COLORREF crTransparent) { int nIndex = (int)m_IDs.GetSize(); while(nIndex--) { if(m_IDs.GetAt(nIndex)==nID) { return nIndex*MENU_ICONS; } } // Try to load the bitmap for getting dimension HBITMAP hBitmap = LoadColorBitmap(MAKEINTRESOURCE(nID),0); if(hBitmap!=NULL) { CBitmap temp; temp.Attach(hBitmap); BITMAP bitmap = {0}; if(!temp.GetBitmap(&bitmap)) { return -1; } if(m_IconsList.GetSafeHandle()==NULL) { m_IconsList.Create(bitmap.bmWidth,bitmap.bmHeight,ILC_COLORDDB|ILC_MASK,0,10); } else { CSize size = GetIconSize(); // Wrong size? if(size.cx!=bitmap.bmWidth || size.cy!=bitmap.bmHeight) { return -1; } } m_TranspColors.Add(crTransparent); m_IDs.Add(nID); nIndex = m_IconsList.Add(&temp,crTransparent); HICON hIcon = m_IconsList.ExtractIcon(nIndex); AddGloomIcon(hIcon); AddGrayIcon(hIcon); DestroyIcon(hIcon); //SetBlendImage(); return nIndex; } return -1; } void CSkinMenuBitmaps::OnSysColorChange() { int nCount = (int)m_IDs.GetSize(); for(int nIndex=0;nIndex<nCount;nIndex+=MENU_ICONS) { //Todo reload icons HICON hIcon = m_IconsList.ExtractIcon(nIndex); AddGloomIcon(hIcon,nIndex+1); AddGrayIcon(hIcon,nIndex+2); DestroyIcon(hIcon); } } int CSkinMenuBitmaps::Add(HICON hIcon, UINT nID) { ICONINFO iconInfo = {0}; if(!GetIconInfo(hIcon,&iconInfo)) { return -1; } CBitmap temp; temp.Attach(iconInfo.hbmColor); ::DeleteObject(iconInfo.hbmMask); BITMAP bitmap = {0}; if(!temp.GetBitmap(&bitmap)) { return -1; } if(m_IconsList.GetSafeHandle()==NULL) { m_IconsList.Create(bitmap.bmWidth,bitmap.bmHeight,ILC_COLORDDB|ILC_MASK,0,10); } else { CSize size = GetIconSize(); // Wrong size? if(size.cx!=bitmap.bmWidth || size.cy!=bitmap.bmHeight) { return -1; } } if(nID) { int nIndex = (int)m_IDs.GetSize(); while(nIndex--) { if(m_IDs.GetAt(nIndex)==nID) { // We found the index also replace the icon nIndex = nIndex*MENU_ICONS; m_IconsList.Replace(nIndex,hIcon); AddGloomIcon(hIcon,nIndex+1); AddGrayIcon(hIcon,nIndex+2); return nIndex; } } } COLORREF clr = CLR_NONE; m_TranspColors.Add(clr); m_IDs.Add(nID); int nIndex = m_IconsList.Add(hIcon); AddGloomIcon(hIcon); AddGrayIcon(hIcon); return nIndex; } int CSkinMenuBitmaps::Add(CBitmap* pBitmap, COLORREF crTransparent) { ASSERT(pBitmap); BITMAP bitmap = {0}; if(!pBitmap->GetBitmap(&bitmap)) { return -1; } if(m_IconsList.GetSafeHandle()==NULL) { m_IconsList.Create(bitmap.bmWidth,bitmap.bmHeight,ILC_COLORDDB|ILC_MASK,0,10); } else { CSize size = GetIconSize(); // Wrong size? if(size.cx!=bitmap.bmWidth || size.cy!=bitmap.bmHeight) { return -1; } } UINT nID = 0; m_TranspColors.Add(crTransparent); m_IDs.Add(nID); int nIndex = m_IconsList.Add(pBitmap,crTransparent); HICON hIcon = m_IconsList.ExtractIcon(nIndex); AddGloomIcon(hIcon); AddGrayIcon(hIcon); DestroyIcon(hIcon); //SetBlendImage(); return nIndex; } ////////////////////////////////////////////////////////////////////// // Construction/Destruction ////////////////////////////////////////////////////////////////////// IMPLEMENT_DYNAMIC(CSkinMenuItemData,CObject); CSkinMenuItemData::CSkinMenuItemData() : m_nTitleFlags(0), m_nFlags(0), m_nID(0), m_nSyncFlag(0), m_pData(NULL), m_pMenuIcon(NULL), m_nMenuIconOffset(-1) { } CSkinMenuItemData::~CSkinMenuItemData() { // it's a safe release. Do not care for NULL pointers. m_pMenuIcon->Release(); } // Get the string, along with (manufactured) accelerator text. CString CSkinMenuItemData::GetString (HACCEL hAccel) { if (m_nFlags & MF_POPUP ) { // No accelerators if we're the title of a popup menu. Otherwise we get spurious accels hAccel = NULL; } CString s = m_szMenuText; int iTabIndex = s.Find ('\t'); if (!hAccel || iTabIndex>= 0) // Got one hard coded in, or we're a popup menu { if (!hAccel && iTabIndex>= 0) { s = s.Left (iTabIndex); } return s; } // OK, we've got to go hunting through the default accelerator. if (hAccel == INVALID_HANDLE_VALUE) { hAccel = NULL; CFrameWnd *pFrame = DYNAMIC_DOWNCAST(CFrameWnd, AfxGetMainWnd ()); // No frame. Maybe we're part of a dialog app. etc. if (pFrame) { hAccel = pFrame->GetDefaultAccelerator (); } } // No default found, or we've turned accelerators off. if (hAccel == NULL) { return s; } // Get the number of entries int nEntries = ::CopyAcceleratorTable (hAccel, NULL, 0); if (nEntries) { ACCEL *pAccel = (ACCEL *)_alloca(nEntries*sizeof(ACCEL)); if (::CopyAcceleratorTable (hAccel, pAccel, nEntries)) { CString sAccel; for (int n = 0; n < nEntries; n++) { if (pAccel [n].cmd != (WORD) m_nID) { continue; } if (!sAccel.IsEmpty ()) { sAccel += _T(", "); } // Translate the accelerator into more useful code. if (pAccel [n].fVirt & FALT) sAccel += _T("Alt+"); if (pAccel [n].fVirt & FCONTROL) sAccel += _T("Ctrl+"); if (pAccel [n].fVirt & FSHIFT) sAccel += _T("Shift+"); if (pAccel [n].fVirt & FVIRTKEY) { TCHAR keyname[64]; UINT vkey = MapVirtualKey(pAccel [n].key, 0)<<16; GetKeyNameText(vkey, keyname, sizeof(keyname)); sAccel += keyname; } else { sAccel += (TCHAR)pAccel [n].key; } } if (!sAccel.IsEmpty ()) // We found one! { s += '\t'; s += sAccel; } } } return s; } void CSkinMenuItemData::SetString(LPCTSTR szMenuText) { m_szMenuText = szMenuText; } #if defined(_DEBUG) || defined(_AFXDLL) // Diagnostic Support void CSkinMenuItemData::AssertValid() const { CObject::AssertValid(); } void CSkinMenuItemData::Dump(CDumpContext& dc) const { CObject::Dump(dc); dc << _T("MenuItem: ") << m_szMenuText << _T("\n"); } #endif ////////////////////////////////////////////////////////////////////// // Construction/Destruction ////////////////////////////////////////////////////////////////////// IMPLEMENT_DYNAMIC(CSkinMenuItemDataTitle,CSkinMenuItemData); CSkinMenuItemDataTitle::CSkinMenuItemDataTitle() : m_clrTitle(CLR_DEFAULT), m_clrLeft(CLR_DEFAULT), m_clrRight(CLR_DEFAULT) { } CSkinMenuItemDataTitle::~CSkinMenuItemDataTitle() { } ////////////////////////////////////////////////////////////////////// // Construction/Destruction ////////////////////////////////////////////////////////////////////// IMPLEMENT_DYNAMIC(CSkinMenu,CMenu); // actual selectet menu-draw mode //CSkinMenuTheme* CSkinMenu::m_pActMenuDrawing = NULL; CTypedPtrList<CPtrList, CSkinMenuIcons*>* CSkinMenu::m_pSharedMenuIcons = NULL; // Gloabal logfont for all menutitles LOGFONT CSkinMenu::m_MenuTitleFont = {16, 0, 0, 0, FW_BOLD, 0, 0, 0, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH,_T("宋体") }; void CSkinMenu::SetMenuTitleFont(CFont* pFont) { ASSERT(pFont); pFont->GetLogFont(&m_MenuTitleFont); } void CSkinMenu::SetMenuTitleFont(LOGFONT* pLogFont) { ASSERT(pLogFont); m_MenuTitleFont = *pLogFont; } LOGFONT CSkinMenu::GetMenuTitleFont() { return m_MenuTitleFont; } DWORD CSkinMenu::m_dwLastActiveItem = NULL; // how the menu's are drawn in winXP BOOL CSkinMenu::m_bEnableXpBlending = TRUE; BOOL CSkinMenu::m_bNewMenuBorderAllMenu = TRUE; BOOL CSkinMenu::m_bSelectDisable = TRUE; // Jan-12-2005 - Mark P. Peterson - mpp@rhinosoft.com - http://www.RhinoSoft.com/ // added so the gloom value can be adjusted // 50 is the default, may be too high, 20 is subtle int CSkinMenu::m_nGloomFactor = 50; const Win32Type g_Shell = IsShellType(); // one instance of the hook for menu-subclassing static CSkinMenuHook SkinMenuHookInstance; CSkinMenu::CSkinMenu(HMENU hParent) : m_hTempOwner(NULL), m_hParentMenu(hParent), m_bIsPopupMenu(TRUE), m_dwOpenMenu(NULL), m_LastActiveMenuRect(0,0,0,0), m_pData(NULL), m_hAccelToDraw((HACCEL)INVALID_HANDLE_VALUE) { // O.S. - no dynamic icons by default m_bDynIcons = FALSE; // Icon sizes default to 16 x 16 m_iconX = 18; m_iconY = 16; m_selectcheck = -1; m_unselectcheck = -1; m_checkmaps=NULL; m_checkmapsshare=FALSE; // set the color used for the transparent background in all bitmaps m_bitmapBackground = CLR_DEFAULT; m_crBackground = ::GetSysColor(COLOR_MENU); m_crText =::GetSysColor(COLOR_MENUTEXT); m_crTextSelected =::GetSysColor(COLOR_MENUTEXT); m_crLeft=RGB(196,229,251); m_crSelectedFill = RGB(0,190,245); } CSkinMenu::~CSkinMenu() { DestroyMenu(); } COLORREF CSkinMenu::GetMenuColor(HMENU hMenu) { if(hMenu!=NULL) { MENUINFO menuInfo={0}; menuInfo.cbSize = sizeof(menuInfo); menuInfo.fMask = MIM_BACKGROUND; if(::GetMenuInfo(hMenu,&menuInfo) && menuInfo.hbrBack) { LOGBRUSH logBrush; if(GetObject(menuInfo.hbrBack,sizeof(LOGBRUSH),&logBrush)) { return logBrush.lbColor; } } } if(IsShellType()==WinXP) { BOOL bFlatMenu = FALSE; // theme ist not checket, that must be so if( (SystemParametersInfo(SPI_GETFLATMENU,0,&bFlatMenu,0) && bFlatMenu==TRUE) ) { return GetSysColor(COLOR_MENUBAR); } } return GetSysColor(COLOR_MENU); } COLORREF CSkinMenu::GetMenuBarColorXP() { // Win95 or WinNT do not support to change the menubarcolor if(IsShellType()==Win95 || IsShellType()==WinNT4) { return GetSysColor(COLOR_MENU); } return GetSysColor(COLOR_3DFACE); } COLORREF CSkinMenu::GetMenuBarColor(HMENU hMenu) { if(hMenu!=NULL) { MENUINFO menuInfo = {0}; menuInfo.cbSize = sizeof(menuInfo); menuInfo.fMask = MIM_BACKGROUND; if(::GetMenuInfo(hMenu,&menuInfo) && menuInfo.hbrBack) { LOGBRUSH logBrush; if(GetObject(menuInfo.hbrBack,sizeof(LOGBRUSH),&logBrush)) { return logBrush.lbColor; } } } if(IsShellType()==WinXP) { BOOL bFlatMenu = FALSE; if(SystemParametersInfo(SPI_GETFLATMENU,0,&bFlatMenu,0) && bFlatMenu==TRUE) { return GetSysColor(COLOR_MENUBAR); } } // May-05-2005 - Mark P. Peterson (mpp@rhinosoft.com) - Changed to use the menubar color, I could not find why COLOR_MENU should // be used when not flat and no XP Theme is active. The problem is that using this shows the wrong color in any other theme, when // the background color of menus is something other than the same color of the menu bar. return (GetMenuBarColorXP()); // return GetSysColor(COLOR_MENU); } void CSkinMenu::SetLastMenuRect(HDC hDC, LPRECT pRect) { if(!m_bIsPopupMenu) { HWND hWnd = WindowFromDC(hDC); if(hWnd && pRect) { CRect Temp; GetWindowRect(hWnd,Temp); m_LastActiveMenuRect = *pRect; m_LastActiveMenuRect.OffsetRect(Temp.TopLeft()); #ifdef _TRACE_MENU_ TRACE(_T("ActiveRect: (%ld,%ld,%ld,%ld)\n"),m_LastActiveMenuRect.left,m_LastActiveMenuRect.top,m_LastActiveMenuRect.right,m_LastActiveMenuRect.bottom); #endif } } } void CSkinMenu::SetLastMenuRect(LPRECT pRect) { ASSERT(pRect); m_LastActiveMenuRect = *pRect; } BOOL CSkinMenu::IsNewShell() { return (g_Shell>=Win95); } BOOL CSkinMenu::OnMeasureItem(const MSG* pMsg) { if(pMsg->message==WM_MEASUREITEM) { LPMEASUREITEMSTRUCT lpMIS = (LPMEASUREITEMSTRUCT)pMsg->lParam; if(lpMIS->CtlType==ODT_MENU) { CMenu* pMenu=NULL; if(::IsMenu(HMENU(lpMIS->itemID)) ) { pMenu = CMenu::FromHandlePermanent(HMENU(lpMIS->itemID) ); } else { _AFX_THREAD_STATE* pThreadState = AfxGetThreadState (); if (pThreadState->m_hTrackingWindow == pMsg->hwnd) { // start from popup pMenu = FindPopupMenuFromIDData(pThreadState->m_hTrackingMenu,lpMIS->itemID,lpMIS->itemData); } if(pMenu==NULL) { // start from menubar pMenu = FindPopupMenuFromIDData(::GetMenu(pMsg->hwnd),lpMIS->itemID,lpMIS->itemData); if(pMenu==NULL) { // finaly start from system menu. pMenu = FindPopupMenuFromIDData(::GetSystemMenu(pMsg->hwnd,FALSE),lpMIS->itemID,lpMIS->itemData); #ifdef USE_NEW_MENU_BAR if(!pMenu) { // Support for new menubar static UINT WM_GETMENU = ::RegisterWindowMessage(_T("CSkinMenuBar::WM_GETMENU")); pMenu = FindPopupMenuFromIDData((HMENU)::SendMessage(pMsg->hwnd,WM_GETMENU,0,0),lpMIS->itemID,lpMIS->itemData); } #endif } } } if(pMenu!=NULL) { #ifdef _TRACE_MENU_ UINT oldWidth = lpMIS->itemWidth; #endif //_TRACE_MENU_ pMenu->MeasureItem(lpMIS); #ifdef _TRACE_MENU_ TRACE(_T("NewMenu MeasureItem: ID:0x08%X, oW:0x%X, W:0x%X, H:0x%X\n"),lpMIS->itemID,oldWidth,lpMIS->itemWidth,lpMIS->itemHeight); #endif //_TRACE_MENU_ return TRUE; } } } return FALSE; } CMenu* CSkinMenu::FindPopupMenuFromID(HMENU hMenu, UINT nID) { // check for a valid menu-handle if ( ::IsMenu(hMenu)) { CMenu *pMenu = CMenu::FromHandlePermanent(hMenu); if(pMenu) { return FindPopupMenuFromID(pMenu,nID); } } return NULL; } CMenu* CSkinMenu::FindPopupMenuFromIDData(HMENU hMenu, UINT nID, ULONG_PTR pData) { // check for a valid menu-handle if ( ::IsMenu(hMenu)) { CMenu *pMenu = CMenu::FromHandlePermanent(hMenu); if(pMenu) { return FindPopupMenuFromIDData(pMenu,nID,pData); } } return NULL; } CMenu* CSkinMenu::FindPopupMenuFromIDData(CMenu* pMenu, UINT nID, ULONG_PTR pData) { if(!pMenu || !IsMenu(pMenu->m_hMenu)) { return NULL; } ASSERT_VALID(pMenu); // walk through all items, looking for ID match UINT nItems = pMenu->GetMenuItemCount(); for (int iItem = 0; iItem < (int)nItems; iItem++) { CMenu* pPopup = pMenu->GetSubMenu(iItem); if (pPopup!=NULL) { // recurse to child popup pPopup = FindPopupMenuFromIDData(pPopup, nID, pData); // check popups on this popup if (pPopup != NULL) { return pPopup; } } else if (pMenu->GetMenuItemID(iItem) == nID) { MENUITEMINFO MenuItemInfo = {0}; MenuItemInfo.cbSize = sizeof(MenuItemInfo); MenuItemInfo.fMask = MIIM_DATA; if(pMenu->GetMenuItemInfo(iItem,&MenuItemInfo,TRUE)) { if(MenuItemInfo.dwItemData==pData) { // it is a normal item inside our popup return pMenu; } } } } // not found return NULL; } CMenu* CSkinMenu::FindPopupMenuFromID(CMenu* pMenu, UINT nID) { if(!pMenu || !IsMenu(pMenu->m_hMenu)) { return NULL; } ASSERT_VALID(pMenu); // walk through all items, looking for ID match UINT nItems = pMenu->GetMenuItemCount(); for (int iItem = 0; iItem < (int)nItems; iItem++) { CMenu* pPopup = pMenu->GetSubMenu(iItem); if (pPopup != NULL) { // recurse to child popup pPopup = FindPopupMenuFromID(pPopup, nID); // check popups on this popup if (pPopup != NULL) { return pPopup; } } else if (pMenu->GetMenuItemID(iItem) == nID) { // it is a normal item inside our popup return pMenu; } } // not found return NULL; } BOOL CSkinMenu::DestroyMenu() { // Destroy Sub menus: int nIndex = (int)m_SubMenus.GetSize(); while(nIndex--) { // Destroy only if we createt it!!!!! CSkinMenu* pMenu = DYNAMIC_DOWNCAST(CSkinMenu,CMenu::FromHandlePermanent(m_SubMenus[nIndex])); if(pMenu) { delete pMenu; } } m_SubMenus.RemoveAll(); // Destroy menu data nIndex = (int)m_MenuItemList.GetSize(); while(nIndex--) { delete(m_MenuItemList[nIndex]); } m_MenuItemList.RemoveAll(); if(m_checkmaps&&!m_checkmapsshare) { delete m_checkmaps; m_checkmaps=NULL; } // Call base-class implementation last: return(CMenu::DestroyMenu()); } HMENU CSkinMenu::GetParent() { return m_hParentMenu; } BOOL CSkinMenu::IsPopup() { return m_bIsPopupMenu; } BOOL CSkinMenu::SetPopup(BOOL bIsPopup) { BOOL bOldFlag = m_bIsPopupMenu; m_bIsPopupMenu = bIsPopup; return bOldFlag; } BOOL CSkinMenu::SetSelectDisableMode(BOOL mode) { BOOL bOldMode = m_bSelectDisable; m_bSelectDisable=mode; return bOldMode; } BOOL CSkinMenu::GetSelectDisableMode() { return m_bSelectDisable; } BOOL CSkinMenu::SetXpBlending(BOOL bEnable) { BOOL bOldMode = m_bEnableXpBlending; m_bEnableXpBlending = bEnable; return bOldMode; } BOOL CSkinMenu::GetXpBlending() { return m_bEnableXpBlending; } // Jan-12-2005 - Mark P. Peterson - mpp@rhinosoft.com - http://www.RhinoSoft.com/ // added SetGloomFactor() and GetGloomFactor() so that the glooming can be done in a more or less subtle way int CSkinMenu::SetGloomFactor(int nGloomFactor) { int nOldGloomFactor = m_nGloomFactor; // set the new gloom factor m_nGloomFactor = nGloomFactor; // return the previous gloom factor return (nOldGloomFactor); } // SetGloomFactor int CSkinMenu::GetGloomFactor() { // return the current gloom factor return (m_nGloomFactor); } // GetGloomFactor // Function to set how default menu border were drawn //(enable=TRUE means that all menu in the application has the same border) BOOL CSkinMenu::SetNewMenuBorderAllMenu(BOOL bEnable /* =TRUE*/) { BOOL bOldMode = m_bNewMenuBorderAllMenu; m_bNewMenuBorderAllMenu = bEnable; return bOldMode; } BOOL CSkinMenu::GetNewMenuBorderAllMenu() { return m_bNewMenuBorderAllMenu; } void CSkinMenu::OnSysColorChange() { static DWORD dwLastTicks = 0; DWORD dwAktTicks = GetTickCount(); // Last Update 2 sec if((dwAktTicks-dwLastTicks)>2000) { dwLastTicks = dwAktTicks; if(m_pSharedMenuIcons) { POSITION pos = m_pSharedMenuIcons->GetHeadPosition(); while(pos) { CSkinMenuIcons* pMenuIcons = m_pSharedMenuIcons->GetNext(pos); pMenuIcons->OnSysColorChange(); } } } } void CSkinMenu::MeasureItem( LPMEASUREITEMSTRUCT lpMIS ) { BOOL bIsMenuBar = IsMenuBar(HMENU(lpMIS->itemID)); if(!bIsMenuBar && m_hParentMenu && !FindMenuItem(lpMIS->itemID)) //::IsMenu(HMENU(lpMIS->itemID)) ) { CSkinMenu* pMenu = DYNAMIC_DOWNCAST(CSkinMenu,CMenu::FromHandlePermanent(m_hParentMenu)); if(pMenu) { MeasureItem_WinXP(lpMIS,bIsMenuBar); return; } } MeasureItem_WinXP(lpMIS,bIsMenuBar); } void CSkinMenu::DrawItem (LPDRAWITEMSTRUCT lpDIS) { BOOL bIsMenuBar = m_hParentMenu ? FALSE: ((m_bIsPopupMenu)?FALSE:TRUE); if(bIsMenuBar && m_dwLastActiveItem==lpDIS->itemData) { if(! (lpDIS->itemState&ODS_HOTLIGHT) ) { // Mark for redraw helper for win 98 m_dwLastActiveItem = NULL; } } DrawItem_WinXP(lpDIS,bIsMenuBar); } // Erase the Background of the menu BOOL CSkinMenu::EraseBkgnd(HWND hWnd, HDC hDC) { CDC* pDC = CDC::FromHandle (hDC); CRect Rect; // Get the size of the menu... GetClientRect(hWnd, Rect ); pDC->FillSolidRect (Rect,GetMenuColor()); return TRUE; } void CSkinMenu::DrawTitle(LPDRAWITEMSTRUCT lpDIS,BOOL bIsMenuBar) { DrawMenuTitle(lpDIS,bIsMenuBar); } void CSkinMenu::DrawMenuTitle(LPDRAWITEMSTRUCT lpDIS, BOOL bIsMenuBar) { UNREFERENCED_PARAMETER(bIsMenuBar); CDC* pDC = CDC::FromHandle(lpDIS->hDC); CSkinMenuItemData* pMenuData = (CSkinMenuItemData*)(lpDIS->itemData); ASSERT(pMenuData); COLORREF colorWindow = GetSysColor(COLOR_WINDOW); COLORREF colorMenuBar = GetMenuColor(); COLORREF colorLeft = MixedColor(colorWindow,colorMenuBar); COLORREF colorRight = ::GetSysColor(COLOR_ACTIVECAPTION); COLORREF colorText = ::GetSysColor(COLOR_CAPTIONTEXT); CSize iconSize(0,0); if(pMenuData->m_nMenuIconOffset!=(-1) && pMenuData->m_pMenuIcon) { iconSize = pMenuData->m_pMenuIcon->GetIconSize(); if(iconSize!=CSize(0,0)) { iconSize += CSize(4,4); } } CSkinMenuItemDataTitle* pItem = DYNAMIC_DOWNCAST(CSkinMenuItemDataTitle,pMenuData); if(pItem) { if(pItem->m_clrRight!=CLR_DEFAULT) { colorRight = pItem->m_clrRight; } if(pItem->m_clrLeft!=CLR_DEFAULT) { colorLeft = pItem->m_clrLeft; } if(pItem->m_clrTitle!=CLR_DEFAULT) { colorText = pItem->m_clrTitle; } } CRect rcClipBox; HWND hWnd = ::WindowFromDC(lpDIS->hDC); // try to get the real size of the client window if(hWnd==NULL || !GetClientRect(hWnd,rcClipBox) ) { // when we have menu animation the DC is a memory DC pDC->GetClipBox(rcClipBox); } // draw the title bar CRect rect = lpDIS->rcItem; CPoint TextPoint; CFont Font; LOGFONT MyFont = m_MenuTitleFont; if(pMenuData->m_nTitleFlags&MFT_SIDE_TITLE) { rect.top = rcClipBox.top; rect.bottom = rcClipBox.bottom; rect.right += GetSystemMetrics(SM_CXMENUCHECK); MyFont.lfOrientation = 900; MyFont.lfEscapement = 900; TextPoint = CPoint(rect.left+2, rect.bottom-4-iconSize.cy); } else { MyFont.lfOrientation = 0; MyFont.lfEscapement = 0; TextPoint = CPoint(rect.left+2+iconSize.cx, rect.top); } Font.CreateFontIndirect(&MyFont); CFont *pOldFont = pDC->SelectObject(&Font); SIZE size = {0,0}; VERIFY(::GetTextExtentPoint32(pDC->m_hDC,pMenuData->m_szMenuText,pMenuData->m_szMenuText.GetLength(),&size)); COLORREF oldColor = pDC->SetTextColor(colorText); int OldMode = pDC->SetBkMode(TRANSPARENT); if(pMenuData->m_nTitleFlags&MFT_GRADIENT) { if(pMenuData->m_nTitleFlags&MFT_SIDE_TITLE) { DrawGradient1(pDC,rect,colorLeft,colorRight,false); } else { DrawGradient1(pDC,rect,colorRight,colorLeft,true); } } else { if(pMenuData->m_nTitleFlags&MFT_ROUND) { if(pMenuData->m_nTitleFlags&MFT_SIDE_TITLE) { TextPoint.y-=2; rect.right = rect.left+size.cy+4; } else { int maxSpace = ((rect.Width()-size.cx)/2); TextPoint.x+=min(maxSpace,10); } CBrush brush(colorRight); CPen* pOldPen = (CPen*)pDC->SelectStockObject(WHITE_PEN); CBrush* pOldBrush = pDC->SelectObject(&brush); pDC->RoundRect(rect,CPoint(10,10)); pDC->SelectObject(pOldBrush); pDC->SelectObject(pOldPen); } else { pDC->FillSolidRect(rect,colorRight); } } if (pMenuData->m_nTitleFlags&MFT_SUNKEN) { pDC->Draw3dRect(rect,GetSysColor(COLOR_3DSHADOW),GetSysColor(COLOR_3DHILIGHT)); } if (pMenuData->m_nTitleFlags&MFT_CENTER) { if (pMenuData->m_nTitleFlags&MFT_SIDE_TITLE) { TextPoint.y = rect.bottom - ((rect.Height()-size.cx-iconSize.cy)>>1)-iconSize.cy; } else { TextPoint.x = rect.left + ((rect.Width()-size.cx-iconSize.cx)>>1)+iconSize.cx; } } pDC->TextOut(TextPoint.x,TextPoint.y, pMenuData->GetString(m_bDrawAccelerators ? m_hAccelToDraw : NULL)); if(pMenuData->m_nMenuIconOffset!=(-1) && pMenuData->m_pMenuIcon) { CPoint ptImage = TextPoint; if (pMenuData->m_nTitleFlags&MFT_SIDE_TITLE) { ptImage.y += 2; } else { ptImage.x -= iconSize.cx; ptImage.y += 2; } // draws the icon HICON hDrawIcon2 = pMenuData->m_pMenuIcon->m_IconsList.ExtractIcon(pMenuData->m_nMenuIconOffset); pDC->DrawState(ptImage, iconSize-CSize(4,4), hDrawIcon2, DSS_NORMAL,(HBRUSH)NULL); DestroyIcon(hDrawIcon2); } if(pMenuData->m_nTitleFlags&MFT_LINE) { if(pMenuData->m_nTitleFlags&MFT_SIDE_TITLE) { CRect rect2(rect.left+20,rect.top+5,rect.left+22,rect.bottom-5); pDC->Draw3dRect(rect2,GetSysColor(COLOR_3DSHADOW),GetSysColor(COLOR_3DHILIGHT)); rect2.OffsetRect(3,0); rect2.InflateRect(0,-10); pDC->Draw3dRect(rect2,GetSysColor(COLOR_3DSHADOW),GetSysColor(COLOR_3DHILIGHT)); } else { CRect rect2(rect.left+2,rect.bottom-7,rect.right-2,rect.bottom-5); pDC->Draw3dRect(rect2,GetSysColor(COLOR_3DHILIGHT),GetSysColor(COLOR_3DSHADOW)); rect2.OffsetRect(0,3); rect2.InflateRect(-10,0); pDC->Draw3dRect(rect2,GetSysColor(COLOR_3DSHADOW),GetSysColor(COLOR_3DHILIGHT)); } } pDC->SetBkMode(OldMode); pDC->SetTextColor(oldColor); pDC->SelectObject(pOldFont); } void CSkinMenu::DrawItem_WinXP(LPDRAWITEMSTRUCT lpDIS, BOOL bIsMenuBar) { ASSERT(lpDIS != NULL); CSkinMenuItemData* pMenuData = (CSkinMenuItemData*)(lpDIS->itemData); ASSERT(pMenuData); UINT nFlags = pMenuData->m_nFlags; CRect rc(&lpDIS->rcItem); CMemDC memdc(CDC::FromHandle(lpDIS->hDC), &rc); BOOL bCancel = FALSE; CDC* pDC=&memdc; COLORREF colorWindow = GetSysColor(COLOR_WINDOW); // COLORREF colorMenuBar = bIsMenuBar?GetMenuBarColor(m_hMenu):GetMenuColor(); COLORREF colorMenuBar = GetMenuBarColor(m_hMenu); //COLORREF colorMenu = RGB(234,244,254);//MixedColor(colorWindow,colorMenuBar);右边 //COLORREF colorBitmap = RGB(196,229,251);//MixedColor(GetMenuBarColor(m_hMenu),colorWindow);左边 COLORREF colorMenu = m_crBackground; COLORREF colorBitmap = m_crLeft; //COLORREF colorSel = RGB(0,172,227);//GetXpHighlightColor(); COLORREF colorSel = m_crSelectedFill; COLORREF colorBorder = RGB(0,172,227); //GetSysColor(COLOR_HIGHLIGHT);//DarkenColor(128,colorMenuBar); if(bHighContrast) { colorBorder = GetSysColor(COLOR_BTNTEXT); } if (NumScreenColors() <= 256) { colorBitmap = GetSysColor(COLOR_BTNFACE); } // Better contrast when you have less than 256 colors if(pDC->GetNearestColor(colorMenu)==pDC->GetNearestColor(colorBitmap)) { colorMenu = colorWindow; colorBitmap = colorMenuBar; } //CPen Pen(PS_SOLID,0,GetSysColor(COLOR_HIGHLIGHT)); CPen Pen(PS_SOLID,0,colorBorder); CBrush m_brSel(colorSel); CBrush m_brBitmap(colorBitmap); CRect RectIcon(lpDIS->rcItem); CRect RectText(lpDIS->rcItem); CRect RectSel(lpDIS->rcItem); if(nFlags & MFT_RIGHTORDER) { RectIcon.left = RectIcon.right - (m_iconX + 8); RectText.right = RectIcon.left; } else { RectIcon.right = RectIcon.left + m_iconX + 8; RectText.left = RectIcon.right; } // Draw for Bitmap background pDC->FillSolidRect (RectIcon,colorBitmap); // Draw for Textbackground pDC->FillSolidRect (RectText,colorMenu); // Spacing for submenu only in popups if(nFlags & MFT_RIGHTORDER) { RectText.left += 15; RectText.right -= 4; } else { RectText.left += 4; RectText.right -= 15; } // Flag for highlighted item if(lpDIS->itemState & (ODS_HOTLIGHT|ODS_INACTIVE) ) { lpDIS->itemState |= ODS_SELECTED; } // For keyboard navigation only BOOL bDrawSmallSelection = FALSE; // remove the selected bit if it's grayed out if( (lpDIS->itemState&ODS_GRAYED) && !m_bSelectDisable) { if( lpDIS->itemState & ODS_SELECTED ) { lpDIS->itemState = lpDIS->itemState & (~ODS_SELECTED); DWORD MsgPos = ::GetMessagePos(); if( MsgPos==CSkinMenuHook::m_dwMsgPos ) { bDrawSmallSelection = TRUE; } else { CSkinMenuHook::m_dwMsgPos = MsgPos; } } } // Draw the seperator if( nFlags & MF_SEPARATOR ) { if( pMenuData->m_nTitleFlags & MFT_TITLE ) { DrawTitle(lpDIS,bIsMenuBar); } else { //绘制分隔线 CRect rect; rect.top = RectText.CenterPoint().y; rect.bottom = rect.top+1; if(nFlags & MFT_RIGHTORDER) { rect.right = RectText.right; rect.left = lpDIS->rcItem.left; } else { rect.right = lpDIS->rcItem.right; rect.left = RectText.left; } //DrawGradient12(pDC, rect, RGB(234,244,254), RGB(168,215,240), RGB(234,244,254), TRUE); CRect rc(rect.left, rect.top, rect.right-(rect.Width()/2), rect.bottom); DrawGradient1(pDC,rc,RGB(234,244,254), RGB(168,215,240), TRUE); rc.OffsetRect(0,1); DrawGradient1(pDC,rc,RGB(234,244,254), RGB(255,255,255), TRUE); rc.SetRect(rect.right-(rect.Width()/2), rect.top, rect.right, rect.bottom); DrawGradient1(pDC,rc,RGB(168,215,240), RGB(234,244,254), TRUE); rc.OffsetRect(0,1); DrawGradient1(pDC,rc,RGB(255,255,255), RGB(234,244,254), TRUE); } } else { //绘制选区 if( (lpDIS->itemState & ODS_SELECTED) && !(lpDIS->itemState & ODS_INACTIVE) ) { CRgn rgn; CRect rcRegion = RectSel; rcRegion.OffsetRect(-rcRegion.TopLeft()); //创建区域 rgn.CreateRoundRectRgn(rcRegion.left, rcRegion.top, rcRegion.right+1, rcRegion.bottom+1, 3, 3); int nSaveDC = pDC->SaveDC(); pDC->SelectClipRgn(&rgn); //梯度填充 DrawGradient1(pDC, RectSel, colorSel,colorSel, FALSE); pDC->RestoreDC(nSaveDC); rgn.DeleteObject(); } else if (bDrawSmallSelection) { pDC->FillSolidRect(RectSel,colorMenu); // Draw the selection for keyboardnavigation CPen* pOldPen = pDC->SelectObject(&Pen); CBrush* pOldBrush = (CBrush*)pDC->SelectStockObject(HOLLOW_BRUSH); pDC->Rectangle(RectSel); pDC->SelectObject(pOldBrush); pDC->SelectObject(pOldPen); } UINT state = lpDIS->itemState; BOOL standardflag=FALSE; BOOL selectedflag=FALSE; BOOL disableflag=FALSE; BOOL checkflag=FALSE; CString strText = pMenuData->GetString(m_bDrawAccelerators ? m_hAccelToDraw : NULL); if( (state&ODS_CHECKED) && (pMenuData->m_nMenuIconOffset<0) ) { if(state&ODS_SELECTED && m_selectcheck>0) { checkflag=TRUE; } else if(m_unselectcheck>0) { checkflag=TRUE; } } else if(pMenuData->m_nMenuIconOffset != -1) { standardflag=TRUE; if(state&ODS_SELECTED) { selectedflag=TRUE; } else if(state&ODS_GRAYED) { disableflag=TRUE; } } // draw the menutext if(!strText.IsEmpty()) { LOGFONT logFontMenu; CFont fontMenu; #ifdef _NEW_MENU_USER_FONT logFontMenu = MENU_USER_FONT; #else NONCLIENTMETRICS nm = {0}; nm.cbSize = sizeof (nm); VERIFY (SystemParametersInfo(SPI_GETNONCLIENTMETRICS,nm.cbSize,&nm,0)); logFontMenu = nm.lfMenuFont; #endif // Default selection? if(state&ODS_DEFAULT) { // Make the font bold logFontMenu.lfWeight = FW_BOLD; } if(state&ODS_DRAW_VERTICAL) { // rotate font 90? logFontMenu.lfOrientation = -900; logFontMenu.lfEscapement = -900; } fontMenu.CreateFontIndirect(&logFontMenu); CString leftStr; CString rightStr; leftStr.Empty(); rightStr.Empty(); int tablocr=strText.ReverseFind(_T('\t')); if(tablocr!=-1) { rightStr=strText.Mid(tablocr+1); leftStr=strText.Left(strText.Find(_T('\t'))); } else { leftStr = strText; } // Draw the text in the correct color: UINT nFormat = DT_LEFT| DT_SINGLELINE|DT_VCENTER; UINT nFormatr = DT_RIGHT|DT_SINGLELINE|DT_VCENTER; if(nFlags&MFT_RIGHTORDER) { nFormat = DT_RIGHT| DT_SINGLELINE|DT_VCENTER|DT_RTLREADING; nFormatr = DT_LEFT|DT_SINGLELINE|DT_VCENTER; } int iOldMode = pDC->SetBkMode( TRANSPARENT); CFont* pOldFont = pDC->SelectObject (&fontMenu); COLORREF OldTextColor; if( (lpDIS->itemState&ODS_GRAYED) || (bIsMenuBar && lpDIS->itemState&ODS_INACTIVE) ) { // Draw the text disabled? OldTextColor = pDC->SetTextColor(GetSysColor(COLOR_GRAYTEXT)); } else { // Draw the text normal if( bHighContrast && !bIsMenuBar && !(state&ODS_SELECTED) ) { OldTextColor = pDC->SetTextColor(GetSysColor(COLOR_WINDOWTEXT)); } else { OldTextColor = pDC->SetTextColor(GetSysColor(COLOR_MENUTEXT)); } } UINT dt_Hide = (lpDIS->itemState & ODS_NOACCEL)?DT_HIDEPREFIX:0; if(dt_Hide && g_Shell>=Win2000) { BOOL bMenuUnderlines = TRUE; if(SystemParametersInfo( SPI_GETKEYBOARDCUES,0,&bMenuUnderlines,0)==TRUE && bMenuUnderlines==TRUE) { // do not hide dt_Hide = 0; } } pDC->DrawText(leftStr,RectText, nFormat|dt_Hide); if(tablocr!=-1) { pDC->DrawText (rightStr,RectText,nFormatr|dt_Hide); } pDC->SetTextColor(OldTextColor); pDC->SelectObject(pOldFont); pDC->SetBkMode(iOldMode); } // Draw the bitmap or checkmarks CRect rect2 = RectText; if(checkflag||standardflag||selectedflag||disableflag) { if(checkflag && m_checkmaps) { CPoint ptImage(RectIcon.left+3,RectIcon.top+4); if(state&ODS_SELECTED) { m_checkmaps->Draw(pDC,1,ptImage,ILD_TRANSPARENT); } else { m_checkmaps->Draw(pDC,0,ptImage,ILD_TRANSPARENT); } } else { CSize size = pMenuData->m_pMenuIcon->GetIconSize(); HICON hDrawIcon = pMenuData->m_pMenuIcon->m_IconsList.ExtractIcon(pMenuData->m_nMenuIconOffset); //CPoint ptImage(RectIcon.left+3,RectIcon.top+ 4); CPoint ptImage( RectIcon.left+3, RectIcon.top + ((RectIcon.Height()-size.cy)>>1) ); // Need to draw the checked state if (state&ODS_CHECKED) { CRect rect = RectIcon; if(nFlags&MFT_RIGHTORDER) { rect.InflateRect (-2,-1,-1,-1); } else { rect.InflateRect (-1,-1,-2,-1); } if(selectedflag) { if (NumScreenColors() > 256) { pDC->FillSolidRect(rect,MixedColor(colorSel,GetSysColor(COLOR_HIGHLIGHT))); } else { pDC->FillSolidRect(rect,colorSel); //GetSysColor(COLOR_HIGHLIGHT) } } else { pDC->FillSolidRect(rect,MixedColor(colorBitmap,GetSysColor(COLOR_HIGHLIGHT))); } CPen* pOldPen = pDC->SelectObject(&Pen); CBrush* pOldBrush = (CBrush*)pDC->SelectStockObject(HOLLOW_BRUSH); pDC->Rectangle(rect); pDC->SelectObject(pOldBrush); pDC->SelectObject(pOldPen); } // Correcting of a smaler icon if(size.cx<m_iconX) { ptImage.x += (m_iconX-size.cx)>>1; } if(state & ODS_DISABLED) { if(m_bEnableXpBlending) { // draws the icon blended HICON hDrawIcon2 = pMenuData->m_pMenuIcon->m_IconsList.ExtractIcon(pMenuData->m_nMenuIconOffset+2); pDC->DrawState(ptImage, size, hDrawIcon2, DSS_NORMAL,(HBRUSH)NULL); DestroyIcon(hDrawIcon2); } else { CBrush Brush; Brush.CreateSolidBrush(pDC->GetNearestColor(DarkenColor(70,colorBitmap))); pDC->DrawState(ptImage, size, hDrawIcon, DSS_MONO, &Brush); } } else { if(selectedflag) { CBrush Brush; // Color of the shade Brush.CreateSolidBrush(pDC->GetNearestColor(DarkenColorXP(colorSel))); if(!(state & ODS_CHECKED)) { ptImage.x++; ptImage.y++; pDC->DrawState(ptImage, size, hDrawIcon, DSS_NORMAL | DSS_MONO, &Brush); ptImage.x-=2; ptImage.y-=2; } pDC->DrawState(ptImage, size, hDrawIcon, DSS_NORMAL,(HBRUSH)NULL); } else { if(m_bEnableXpBlending) { // draws the icon blended HICON hDrawIcon2 = pMenuData->m_pMenuIcon->m_IconsList.ExtractIcon(pMenuData->m_nMenuIconOffset+1); pDC->DrawState(ptImage, size, hDrawIcon2, DSS_NORMAL,(HBRUSH)NULL); DestroyIcon(hDrawIcon2); } else { // draws the icon with normal color pDC->DrawState(ptImage, size, hDrawIcon, DSS_NORMAL,(HBRUSH)NULL); } } } DestroyIcon(hDrawIcon); } } if(pMenuData->m_nMenuIconOffset<0 /*&& state&ODS_CHECKED */ && !checkflag) { MENUITEMINFO info = {0}; info.cbSize = sizeof(info); info.fMask = MIIM_CHECKMARKS; ::GetMenuItemInfo(HMENU(lpDIS->hwndItem),lpDIS->itemID,MF_BYCOMMAND, &info); if(state&ODS_CHECKED || info.hbmpUnchecked) { CRect rect = RectIcon; if(nFlags&MFT_RIGHTORDER) { rect.InflateRect (-2,-1,-1,-1); } else { rect.InflateRect (-1,-1,-2,-1); } // draw the color behind checkmarks if(state&ODS_SELECTED) { if (NumScreenColors() > 256) { pDC->FillSolidRect(rect,MixedColor(colorSel,GetSysColor(COLOR_HIGHLIGHT))); } else { pDC->FillSolidRect(rect,colorSel); } } else { pDC->FillSolidRect(rect,MixedColor(colorBitmap,GetSysColor(COLOR_HIGHLIGHT))); } CPen* pOldPen = pDC->SelectObject(&Pen); CBrush* pOldBrush = (CBrush*)pDC->SelectStockObject(HOLLOW_BRUSH); pDC->Rectangle(rect); pDC->SelectObject(pOldBrush); pDC->SelectObject(pOldPen); if (state&ODS_CHECKED) { CRect rect(RectIcon); rect.InflateRect(2,((m_iconY-RectIcon.Height())>>1)+2); if (!info.hbmpChecked) { // Checkmark DrawSpecialCharStyle(pDC,rect,98,state); } else if(!info.hbmpUnchecked) { // Bullet DrawSpecialCharStyle(pDC,rect,105,state); } else { // Draw Bitmap BITMAP myInfo = {0}; GetObject((HGDIOBJ)info.hbmpChecked,sizeof(myInfo),&myInfo); CPoint Offset = RectIcon.TopLeft() + CPoint((RectIcon.Width()-myInfo.bmWidth)/2,(RectIcon.Height()-myInfo.bmHeight)/2); pDC->DrawState(Offset,CSize(0,0),info.hbmpChecked,DST_BITMAP|DSS_MONO); } } else if(info.hbmpUnchecked) { // Draw Bitmap BITMAP myInfo = {0}; GetObject((HGDIOBJ)info.hbmpUnchecked,sizeof(myInfo),&myInfo); CPoint Offset = RectIcon.TopLeft() + CPoint((RectIcon.Width()-myInfo.bmWidth)/2,(RectIcon.Height()-myInfo.bmHeight)/2); if(state & ODS_DISABLED) { pDC->DrawState(Offset,CSize(0,0),info.hbmpUnchecked,DST_BITMAP|DSS_MONO|DSS_DISABLED); } else { pDC->DrawState(Offset,CSize(0,0),info.hbmpUnchecked,DST_BITMAP|DSS_MONO); } } } else if ((lpDIS->itemID&0xffff)>=SC_SIZE && (lpDIS->itemID&0xffff)<=SC_HOTKEY ) { DrawSpecial_WinXP(pDC,RectIcon,lpDIS->itemID,state); } } } } BOOL CSkinMenu::IsMenuBar(HMENU hMenu) { BOOL bIsMenuBar = FALSE; if(!FindMenuItem((UINT)hMenu)) { if(m_hParentMenu==NULL) { return m_bIsPopupMenu?FALSE:TRUE; } CSkinMenu* pMenu = DYNAMIC_DOWNCAST(CSkinMenu,CMenu::FromHandlePermanent(m_hParentMenu)); if (pMenu!=NULL) { return pMenu->m_bIsPopupMenu?FALSE:TRUE; } } else { // Test for only one item not bar bIsMenuBar = m_hParentMenu ? FALSE: ((m_bIsPopupMenu)?FALSE:TRUE); } return bIsMenuBar; } void CSkinMenu::MeasureItem_WinXP( LPMEASUREITEMSTRUCT lpMIS, BOOL bIsMenuBar ) { ASSERT(lpMIS->itemData); CSkinMenuItemData* pMenuData = (CSkinMenuItemData*)(lpMIS->itemData); UINT nFlag = pMenuData->m_nFlags; if(nFlag & MF_SEPARATOR) { if(pMenuData->m_nTitleFlags&MFT_TITLE) { SIZE size = {0,0}; {// We need this sub-block for releasing the dc // DC of the desktop CClientDC myDC(NULL); CFont font; LOGFONT MyFont = m_MenuTitleFont; MyFont.lfOrientation = 0; MyFont.lfEscapement = 0; font.CreateFontIndirect(&MyFont); CFont* pOldFont = myDC.SelectObject (&font); CString lpstrText = pMenuData->GetString(m_bDrawAccelerators ? m_hAccelToDraw : NULL); VERIFY(::GetTextExtentPoint32(myDC.m_hDC,lpstrText,(int)_tcslen(lpstrText),&size)); // Select old font in myDC.SelectObject(pOldFont); } CSize iconSize(0,0); if(pMenuData->m_nMenuIconOffset!=(-1) && pMenuData->m_pMenuIcon) { iconSize = pMenuData->m_pMenuIcon->GetIconSize(); if(iconSize!=CSize(0,0)) { iconSize += CSize(2,2); } } if(pMenuData->m_nTitleFlags&MFT_SIDE_TITLE) { lpMIS->itemWidth = max(size.cy,iconSize.cx) - GetSystemMetrics(SM_CXMENUCHECK); // Don't make the menu higher than menuitems in it lpMIS->itemHeight = 0; if(pMenuData->m_nTitleFlags&MFT_LINE) { lpMIS->itemWidth += 8; } else if(pMenuData->m_nTitleFlags&MFT_ROUND) { lpMIS->itemWidth += 4; } } else { lpMIS->itemWidth = size.cx + iconSize.cx; lpMIS->itemHeight = max(size.cy,iconSize.cy); if(pMenuData->m_nTitleFlags&MFT_LINE) { lpMIS->itemHeight += 8; } } } else { lpMIS->itemHeight = 3; lpMIS->itemWidth = 3; } } else { SIZE size = {0,0}; //Get pointer to text SK CString itemText = pMenuData->GetString(m_bDrawAccelerators ? m_hAccelToDraw : NULL); { // We need this sub-block for releasing the dc CFont fontMenu; LOGFONT logFontMenu; #ifdef _NEW_MENU_USER_FONT logFontMenu = MENU_USER_FONT; #else NONCLIENTMETRICS nm = {0}; nm.cbSize = sizeof (NONCLIENTMETRICS); VERIFY (SystemParametersInfo(SPI_GETNONCLIENTMETRICS,nm.cbSize,&nm,0)); logFontMenu = nm.lfMenuFont; #endif // Default selection? if (GetDefaultItem(0, FALSE) == pMenuData->m_nID) { // Make the font bold logFontMenu.lfWeight = FW_BOLD; } fontMenu.CreateFontIndirect (&logFontMenu); // DC of the desktop CClientDC myDC(NULL); // Select menu font in... CFont* pOldFont = myDC.SelectObject (&fontMenu); // Check the Key-Shortcut replacing for japanise/chinese calculating space itemText.Replace(_T("\t"),_T("nnn")); VERIFY(::GetTextExtentPoint32(myDC.m_hDC,itemText,itemText.GetLength(),&size)); // Select old font in myDC.SelectObject(pOldFont); }// We need this sub-block for releasing the dc int temp = GetSystemMetrics(SM_CYMENU); // Set width and height: if(nFlag & MF_POPUP) { lpMIS->itemWidth = 2 + m_iconX + 4 + size.cx + GetSystemMetrics(SM_CYMENU); } else { lpMIS->itemWidth = 2 + m_iconX + 4 + size.cx + GetSystemMetrics(SM_CYMENU) / 2; } lpMIS->itemHeight = temp>m_iconY+8 ? temp : m_iconY+7; if(lpMIS->itemHeight<((UINT)size.cy) ) { lpMIS->itemHeight=((UINT)size.cy); } // set status bar as appropriate UINT nItemID = (lpMIS->itemID & 0xFFF0); // Special case for system menu if (nItemID>=SC_SIZE && nItemID<=SC_HOTKEY) { BOOL bGetNext = FALSE; // search the actual menu item for (int j=0;j<m_MenuItemList.GetUpperBound();++j) { CSkinMenuItemData* pTemp = m_MenuItemList[j]; if(pTemp==pMenuData || bGetNext==TRUE) { bGetNext = TRUE; pTemp = m_MenuItemList[j+1]; if(pTemp->m_nID) { lpMIS->itemData = (ULONG_PTR)pTemp; lpMIS->itemID = pTemp->m_nID; UINT nOrgWidth = lpMIS->itemWidth; MeasureItem_WinXP(lpMIS,bIsMenuBar); // Restore old values lpMIS->itemData = (ULONG_PTR)pMenuData; lpMIS->itemID = pMenuData->m_nID; lpMIS->itemWidth = max(lpMIS->itemWidth,nOrgWidth); break; } } } lpMIS->itemHeight = temp; } } //TRACE("IsMenuBar %ld, Height %2ld, width %3ld, ID 0x%08lX \r\n",int(bIsMenuBar),lpMIS->itemHeight,lpMIS->itemWidth,lpMIS->itemID); } void CSkinMenu::SetIconSize (int width, int height) { m_iconX = width; m_iconY = height; } CSize CSkinMenu::GetIconSize() { return CSize(m_iconX,m_iconY); } BOOL CSkinMenu::AppendODMenu(LPCTSTR lpstrText, UINT nFlags, UINT nID, int nIconNormal) { return CSkinMenu::AppendODMenu(lpstrText,nFlags,nID,(CImageList*)NULL,nIconNormal); } BOOL CSkinMenu::AppendODMenu(LPCTSTR lpstrText, UINT nFlags, UINT nID, CBitmap* pBmp) { int nIndex = -1; CSkinMenuIconLock iconLock(GetMenuIcon(nIndex,pBmp)); return AppendODMenu(lpstrText,nFlags,nID,iconLock,nIndex); } BOOL CSkinMenu::AppendODMenu(LPCTSTR lpstrText, UINT nFlags, UINT nID, CImageList* pil, int xoffset) { int nIndex = 0; // Helper for addref and release CSkinMenuIconLock iconLock(GetMenuIcon(nIndex,nID,pil,xoffset)); return AppendODMenu(lpstrText,nFlags,nID,iconLock,nIndex); } BOOL CSkinMenu::AppendODMenu(LPCTSTR lpstrText, UINT nFlags, UINT nID, CSkinMenuIcons* pIcons, int nIndex) { // Add the MF_OWNERDRAW flag if not specified: if(!(nFlags & MF_OWNERDRAW)) { nFlags |= MF_OWNERDRAW; } if(nFlags & MF_POPUP) { CSkinMenu* pSubMenu = DYNAMIC_DOWNCAST(CSkinMenu,CMenu::FromHandlePermanent(HMENU(nID))); if(pSubMenu) { pSubMenu->m_hParentMenu = m_hMenu; } } CSkinMenuItemData* pItemData = new CSkinMenuItemData; m_MenuItemList.Add(pItemData); pItemData->SetString(lpstrText); pIcons->AddRef(); pItemData->m_pMenuIcon->Release(); pItemData->m_pMenuIcon = pIcons; pItemData->m_nFlags = nFlags; pItemData->m_nID = nID; if(pIcons && nIndex>=0) { pItemData->m_nMenuIconOffset = nIndex; CSize size = pIcons->GetIconSize(); m_iconX = max(m_iconX,size.cx); m_iconY = max(m_iconY,size.cy); } else { pItemData->m_nMenuIconOffset = -1; } // for having automated shortcut handling, thank to Mehdy Bohlool if (CMenu::AppendMenu(nFlags&~MF_OWNERDRAW, nID, pItemData->m_szMenuText)) { return CMenu::ModifyMenu( CMenu::GetMenuItemCount()-1, MF_BYPOSITION| nFlags, nID, (LPCTSTR)pItemData ); } return FALSE; } BOOL CSkinMenu::InsertODMenu(UINT nPosition, LPCTSTR lpstrText, UINT nFlags, UINT nID, int nIconNormal) { int nIndex = -1; CSkinMenuIcons* pIcons=NULL; if(nIconNormal>=0) { if(LoadFromToolBar(nID,nIconNormal,nIndex)) { // the nIconNormal is a toolbar pIcons = GetToolbarIcons(nIconNormal); if(pIcons) { nIndex = pIcons->FindIndex(nID); } } else { // the nIconNormal is a bitmap pIcons = GetMenuIcon(nIndex,nIconNormal); } } CSkinMenuIconLock iconLock(pIcons); return InsertODMenu(nPosition,lpstrText,nFlags,nID,iconLock,nIndex); } BOOL CSkinMenu::InsertODMenu(UINT nPosition, LPCTSTR lpstrText, UINT nFlags, UINT nID, CBitmap* pBmp) { int nIndex = -1; CSkinMenuIconLock iconLock(GetMenuIcon(nIndex,pBmp)); return InsertODMenu(nPosition,lpstrText,nFlags,nID,iconLock,nIndex); } BOOL CSkinMenu::InsertODMenu(UINT nPosition, LPCTSTR lpstrText, UINT nFlags, UINT nID, CImageList *pil, int xoffset) { int nIndex = -1; CSkinMenuIconLock iconLock(GetMenuIcon(nIndex,nID,pil,xoffset)); return InsertODMenu(nPosition,lpstrText,nFlags,nID,iconLock,nIndex); } BOOL CSkinMenu::InsertODMenu(UINT nPosition, LPCTSTR lpstrText, UINT nFlags, UINT nID, CSkinMenuIcons* pIcons, int nIndex) { if(!(nFlags & MF_BYPOSITION)) { int iPosition =0; CSkinMenu* pMenu = FindMenuOption(nPosition,iPosition); if(pMenu) { return(pMenu->InsertODMenu(iPosition,lpstrText,nFlags|MF_BYPOSITION,nID,pIcons,nIndex)); } else { return(FALSE); } } if(!nID) { nFlags=MF_SEPARATOR|MF_OWNERDRAW|MF_BYPOSITION; } else if(!(nFlags & MF_OWNERDRAW)) { nFlags |= MF_OWNERDRAW; } if(nFlags & MF_POPUP) { CSkinMenu* pSubMenu = DYNAMIC_DOWNCAST(CSkinMenu,CMenu::FromHandlePermanent(HMENU(nID))); if(pSubMenu) { pSubMenu->m_hParentMenu = m_hMenu; } } //Stephane Clog suggested adding this, believe it or not it's in the help if(nPosition==(UINT)-1) { nPosition = GetMenuItemCount(); } CSkinMenuItemData *pItemData = new CSkinMenuItemData; m_MenuItemList.InsertAt(nPosition,pItemData); pItemData->SetString(lpstrText); pIcons->AddRef(); pItemData->m_pMenuIcon->Release(); pItemData->m_pMenuIcon = pIcons; pItemData->m_nFlags = nFlags; pItemData->m_nID = nID; if(pIcons && nIndex>=0) { pItemData->m_nMenuIconOffset = nIndex; CSize size = pIcons->GetIconSize(); m_iconX = max(m_iconX,size.cx); m_iconY = max(m_iconY,size.cy); } else { pItemData->m_nMenuIconOffset = -1; } // for having automated shortcut handling, thank to Mehdy Bohlool if (CMenu::InsertMenu(nPosition,nFlags&~MF_OWNERDRAW,nID,pItemData->m_szMenuText)) { return CMenu::ModifyMenu(nPosition, MF_BYPOSITION| nFlags, nID, (LPCTSTR)pItemData ); } return FALSE; } // Same as ModifyMenu but replacement for CSkinMenu BOOL CSkinMenu::ModifyODMenu(UINT nPosition, UINT nFlags, UINT nIDNewItem,LPCTSTR lpszNewItem) { if(!(nFlags & MF_BYPOSITION)) { int iPosition =0; CSkinMenu* pMenu = FindMenuOption(nPosition,iPosition); if(pMenu) { return(pMenu->ModifyODMenu(iPosition,nFlags|MF_BYPOSITION,nIDNewItem,lpszNewItem)); } else { return(FALSE); } } UINT nMenuID = GetMenuItemID(nPosition); if(nMenuID==(UINT)-1) { nMenuID = (UINT)::GetSubMenu(m_hMenu,nPosition); } CSkinMenuItemData* pItemData = FindMenuItem(nMenuID); BOOL bRet = CMenu::ModifyMenu(nPosition, nFlags, nIDNewItem,lpszNewItem); if(pItemData) { pItemData->m_nID = nIDNewItem; GetMenuString(nPosition,pItemData->m_szMenuText,MF_BYPOSITION); CMenu::ModifyMenu(nPosition, nFlags|MF_OWNERDRAW, nIDNewItem,(LPCTSTR)pItemData); } if(bRet && (nFlags & MF_POPUP) ) { CSkinMenu* pSubMenu = DYNAMIC_DOWNCAST(CSkinMenu,CMenu::FromHandlePermanent(HMENU(nIDNewItem))); if(pSubMenu) { pSubMenu->m_hParentMenu = m_hMenu; } } return bRet; } BOOL CSkinMenu::ModifyODMenu(UINT nPosition, UINT nFlags, UINT nIDNewItem, const CBitmap* pBmp) { if(!(nFlags & MF_BYPOSITION)) { int iPosition =0; CSkinMenu* pMenu = FindMenuOption(nPosition,iPosition); if(pMenu) { return(pMenu->ModifyODMenu(iPosition,nFlags|MF_BYPOSITION,nIDNewItem,pBmp)); } else { return(FALSE); } } UINT nMenuID = GetMenuItemID(nPosition); if(nMenuID==(UINT)-1) { nMenuID = (UINT)::GetSubMenu(m_hMenu,nPosition); } CSkinMenuItemData* pItemData = FindMenuItem(nMenuID); BOOL bRet = CMenu::ModifyMenu(nPosition, nFlags, nIDNewItem,pBmp); if(pItemData) { pItemData->m_nID = nIDNewItem; pItemData->m_szMenuText.Empty(); CMenu::ModifyMenu(nPosition, nFlags|MF_OWNERDRAW, nIDNewItem,(LPCTSTR)pItemData); } if(bRet && (nFlags & MF_POPUP) ) { CSkinMenu* pSubMenu = DYNAMIC_DOWNCAST(CSkinMenu,CMenu::FromHandlePermanent(HMENU(nIDNewItem))); if(pSubMenu) { pSubMenu->m_hParentMenu = m_hMenu; } } return bRet; } BOOL CSkinMenu::ModifyODMenu(LPCTSTR lpstrText, UINT nID, int nIconNormal) { int nLoc; CSkinMenuItemData* pItemData; CArray<CSkinMenu*,CSkinMenu*>newSubs; CArray<int,int&>newLocs; BOOL bModifyOK = TRUE; // Find the old CSkinMenuItemData structure: CSkinMenu* pSubMenu = FindMenuOption(nID,nLoc); do { if(pSubMenu && nLoc>=0) { pItemData = pSubMenu->m_MenuItemList[nLoc]; } else { // Create a new CSkinMenuItemData structure: pItemData = new CSkinMenuItemData; m_MenuItemList.Add(pItemData); } BOOL bTextChanged = FALSE; ASSERT(pItemData); if(lpstrText && pItemData->m_szMenuText.Compare(lpstrText)!=NULL) { bTextChanged = TRUE; pItemData->SetString(lpstrText); } pItemData->m_nMenuIconOffset=-1; if(nIconNormal>=0) { int nxOffset = -1; CSkinMenuIcons* pIcons=NULL; if(LoadFromToolBar(nID,nIconNormal,nxOffset)) { // the nIconNormal is a toolbar pIcons = GetToolbarIcons(nIconNormal); if(pIcons) { pItemData->m_nMenuIconOffset = pIcons->FindIndex(nID); } } else { // the nIconNormal is a bitmap pIcons = GetMenuIcon(pItemData->m_nMenuIconOffset,nIconNormal); } pIcons->AddRef(); pItemData->m_pMenuIcon->Release(); pItemData->m_pMenuIcon = pIcons; if(pIcons) { CSize size = pIcons->GetIconSize(); pSubMenu->m_iconX = max(pSubMenu->m_iconX,size.cx); pSubMenu->m_iconY = max(pSubMenu->m_iconY,size.cy); } } pItemData->m_nFlags &= ~(MF_BYPOSITION); pItemData->m_nFlags |= MF_OWNERDRAW; pItemData->m_nID = nID; // for having automated shortcut handling if(pSubMenu && bTextChanged) { if(pSubMenu->ModifyMenu(nLoc, MF_BYPOSITION|(pItemData->m_nFlags&~MF_OWNERDRAW), nID,pItemData->m_szMenuText) ) { if(!pSubMenu->ModifyMenu(nLoc, MF_BYPOSITION|pItemData->m_nFlags, nID,(LPCTSTR)pItemData)) bModifyOK = FALSE; } else { bModifyOK = FALSE; } } newSubs.Add(pSubMenu); newLocs.Add(nLoc); if(pSubMenu && nLoc>=0) pSubMenu = FindAnotherMenuOption(nID,nLoc,newSubs,newLocs); else pSubMenu = NULL; }while(pSubMenu); return (CMenu::ModifyMenu(nID,pItemData->m_nFlags,nID,(LPCTSTR)pItemData)) && bModifyOK; } BOOL CSkinMenu::ModifyODMenu(LPCTSTR lpstrText, UINT nID, CImageList *pil, int xoffset) { int nIndex = 0; CSkinMenuIcons* pIcons = GetMenuIcon(nIndex,nID,pil,xoffset); pIcons->AddRef(); BOOL bResult = ModifyODMenu(lpstrText,nID,pIcons,nIndex); pIcons->Release(); return bResult; } BOOL CSkinMenu::ModifyODMenu(LPCTSTR lpstrText, UINT nID, CSkinMenuIcons* pIcons, int xoffset) { ASSERT(pIcons); int nLoc; CSkinMenuItemData *pItemData; CArray<CSkinMenu*,CSkinMenu*>newSubs; CArray<int,int&>newLocs; BOOL bModifyOK = TRUE; // Find the old CSkinMenuItemData structure: CSkinMenu *pSubMenu = FindMenuOption(nID,nLoc); do { if(pSubMenu && nLoc>=0) { pItemData = pSubMenu->m_MenuItemList[nLoc]; } else { // Create a new CSkinMenuItemData structure: pItemData = new CSkinMenuItemData; m_MenuItemList.Add(pItemData); } BOOL bTextChanged = FALSE; ASSERT(pItemData); if(lpstrText && pItemData->m_szMenuText.Compare(lpstrText)!=NULL) { bTextChanged = TRUE; pItemData->SetString(lpstrText); } if(pIcons) { pIcons->AddRef(); pItemData->m_pMenuIcon->Release(); pItemData->m_pMenuIcon = pIcons; pItemData->m_nMenuIconOffset = xoffset; int x=0; int y=0; if(pSubMenu && pIcons->GetIconSize(&x,&y)) { // Correct the size of the menuitem pSubMenu->m_iconX = max(pSubMenu->m_iconX,x); pSubMenu->m_iconY = max(pSubMenu->m_iconY,y); } } else { pItemData->m_nMenuIconOffset = -1; } pItemData->m_nFlags &= ~(MF_BYPOSITION); pItemData->m_nFlags |= MF_OWNERDRAW; pItemData->m_nID = nID; // for having automated shortcut handling if(pSubMenu && bTextChanged) { if(pSubMenu->ModifyMenu(nLoc, MF_BYPOSITION|(pItemData->m_nFlags&~MF_OWNERDRAW), nID,pItemData->m_szMenuText) ) { if(!pSubMenu->ModifyMenu(nLoc, MF_BYPOSITION|pItemData->m_nFlags, nID,(LPCTSTR)pItemData)) bModifyOK = FALSE; } else { bModifyOK = FALSE; } } newSubs.Add(pSubMenu); newLocs.Add(nLoc); if(pSubMenu && nLoc>=0) pSubMenu = FindAnotherMenuOption(nID,nLoc,newSubs,newLocs); else pSubMenu = NULL; } while(pSubMenu); return (CMenu::ModifyMenu(nID,pItemData->m_nFlags,nID,(LPCTSTR)pItemData)) && bModifyOK; } BOOL CSkinMenu::ModifyODMenu(LPCTSTR lpstrText, UINT nID, CBitmap* bmp) { if (bmp) { CImageList temp; temp.Create(m_iconX,m_iconY,ILC_COLORDDB|ILC_MASK,1,1); temp.Add(bmp,GetBitmapBackground()); return ModifyODMenu(lpstrText,nID,&temp,0); } return ModifyODMenu(lpstrText,nID,(CImageList*)NULL,0); } BOOL CSkinMenu::ModifyODMenu(LPCTSTR lpstrText, UINT nID, COLORREF fill, COLORREF border, int hatchstyle) { // Get device context CSize bitmap_size(m_iconX,m_iconY); CBitmap bmp; { CClientDC DC(0); ColorBitmap(&DC,bmp,bitmap_size,fill,border,hatchstyle); } return ModifyODMenu(lpstrText,nID,&bmp); } BOOL CSkinMenu::ModifyODMenu(LPCTSTR lpstrText, LPCTSTR OptionText, int nIconNormal) { int nIndex = 0; CSkinMenu* pOptionMenu = FindMenuOption(OptionText,nIndex); if(pOptionMenu!=NULL && nIndex>=0) { CSkinMenuItemData* pItemData = pOptionMenu->m_MenuItemList[nIndex]; BOOL bTextChanged = FALSE; ASSERT(pItemData); if(lpstrText && pItemData->m_szMenuText.Compare(lpstrText)!=NULL) { bTextChanged = TRUE; pItemData->SetString(lpstrText); } pItemData->m_nMenuIconOffset = nIconNormal; if(nIconNormal>=0) { CSkinMenuIcons* pIcons = GetMenuIcon(pItemData->m_nMenuIconOffset,nIconNormal); pIcons->AddRef(); pItemData->m_pMenuIcon->Release(); pItemData->m_pMenuIcon = pIcons; CSkinMenuBitmaps* pMenuIcon = DYNAMIC_DOWNCAST(CSkinMenuBitmaps,pItemData->m_pMenuIcon); if(pMenuIcon) { CSize size = pMenuIcon->GetIconSize(); pOptionMenu->m_iconX = max(pOptionMenu->m_iconX,size.cx); pOptionMenu->m_iconY = max(pOptionMenu->m_iconY,size.cy); } } // for having automated shortcut handling if(pOptionMenu && bTextChanged) { if(!pOptionMenu->ModifyMenu(nIndex, MF_BYPOSITION|(pItemData->m_nFlags&~MF_OWNERDRAW), pItemData->m_nID,pItemData->m_szMenuText) || !pOptionMenu->ModifyMenu(nIndex, MF_BYPOSITION|pItemData->m_nFlags, pItemData->m_nID,(LPCTSTR)pItemData)) { return FALSE; } } return TRUE; } return FALSE; } CSkinMenuItemData* CSkinMenu::NewODMenu(UINT pos, UINT nFlags, UINT nID, LPCTSTR string) { CSkinMenuItemData* pItemData; pItemData = new CSkinMenuItemData; pItemData->m_nFlags = nFlags; pItemData->m_nID = nID; if(!(nFlags&MF_BITMAP)) { pItemData->SetString (string); } if(nFlags & MF_POPUP) { CSkinMenu* pSubMenu = DYNAMIC_DOWNCAST(CSkinMenu,CMenu::FromHandlePermanent(HMENU(nID))); if(pSubMenu) pSubMenu->m_hParentMenu = m_hMenu; } BOOL bModified = FALSE; if (nFlags&MF_OWNERDRAW) bModified = ModifyMenu(pos,nFlags,nID,(LPCTSTR)pItemData); else if (nFlags&MF_BITMAP) bModified = ModifyMenu(pos,nFlags,nID,(CBitmap*)string); else if (nFlags&MF_SEPARATOR) { ASSERT(nFlags&MF_SEPARATOR); bModified = ModifyMenu(pos,nFlags,nID); } else // (nFlags&MF_STRING) { ASSERT(!(nFlags&MF_OWNERDRAW)); bModified = ModifyMenu(pos,nFlags,nID,pItemData->GetString(m_bDrawAccelerators ? m_hAccelToDraw : NULL)); } if(!bModified) { ShowLastError(_T("Error from Menu: ModifyMenu")); } return(pItemData); }; BOOL CSkinMenu::LoadToolBars(const UINT* arID, int n, HMODULE hInst) { ASSERT(arID); BOOL returnflag = TRUE; for(int i=0;i<n;++i) { if(!LoadToolBar(arID[i],hInst)) returnflag = FALSE; } return(returnflag); } DWORD CSkinMenu::SetMenuIcons(CSkinMenuIcons* pMenuIcons) { ASSERT(pMenuIcons); int nCount = (int)pMenuIcons->m_IDs.GetSize(); while(nCount--) { ModifyODMenu(NULL,pMenuIcons->m_IDs[nCount],pMenuIcons,nCount*MENU_ICONS); } return pMenuIcons->m_dwRefCount; } CSkinMenuIcons* CSkinMenu::GetMenuIcon(int &nIndex, UINT nID, CImageList *pil, int xoffset) { if(pil==NULL || xoffset<0) { nIndex=-1; return NULL; } HICON hIcon = pil->ExtractIcon(xoffset); if(m_pSharedMenuIcons!=NULL) { POSITION pos = m_pSharedMenuIcons->GetHeadPosition(); while(pos) { CSkinMenuBitmaps* pMenuIcon = DYNAMIC_DOWNCAST(CSkinMenuBitmaps,m_pSharedMenuIcons->GetNext(pos)); if(pMenuIcon) { nIndex = pMenuIcon->Add(hIcon,nID); if(nIndex!=-1) { DestroyIcon(hIcon); return pMenuIcon; } } } } else { m_pSharedMenuIcons = new CTypedPtrList<CPtrList, CSkinMenuIcons*>; } CSkinMenuBitmaps* pMenuIcon = new CSkinMenuBitmaps(); pMenuIcon->m_crTransparent = m_bitmapBackground; nIndex = pMenuIcon->Add(hIcon,nID); DestroyIcon(hIcon); if(nIndex!=-1) { m_pSharedMenuIcons->AddTail(pMenuIcon); return pMenuIcon; } delete pMenuIcon; return NULL; } CSkinMenuIcons* CSkinMenu::GetMenuIcon(int &nIndex, int nID) { if(m_pSharedMenuIcons!=NULL) { POSITION pos = m_pSharedMenuIcons->GetHeadPosition(); while(pos) { CSkinMenuBitmaps* pMenuIcon = DYNAMIC_DOWNCAST(CSkinMenuBitmaps,m_pSharedMenuIcons->GetNext(pos)); if(pMenuIcon) { if(m_bDynIcons) { nIndex = pMenuIcon->Add((HICON)(INT_PTR)nID); } else { nIndex = pMenuIcon->Add(nID,m_bitmapBackground); } if(nIndex!=-1) { return pMenuIcon; } } } } else { m_pSharedMenuIcons = new CTypedPtrList<CPtrList, CSkinMenuIcons*>; } CSkinMenuBitmaps* pMenuIcon = new CSkinMenuBitmaps(); pMenuIcon->m_crTransparent = m_bitmapBackground; nIndex = pMenuIcon->Add(nID,m_bitmapBackground); if(nIndex!=-1) { m_pSharedMenuIcons->AddTail(pMenuIcon); return pMenuIcon; } delete pMenuIcon; return NULL; } CSkinMenuIcons* CSkinMenu::GetMenuIcon(int &nIndex, CBitmap* pBmp) { if(pBmp==NULL) { nIndex=-1; return NULL; } if(m_pSharedMenuIcons!=NULL) { POSITION pos = m_pSharedMenuIcons->GetHeadPosition(); while(pos) { CSkinMenuBitmaps* pMenuIcon = DYNAMIC_DOWNCAST(CSkinMenuBitmaps,m_pSharedMenuIcons->GetNext(pos)); if(pMenuIcon) { nIndex = pMenuIcon->Add(pBmp,m_bitmapBackground); if(nIndex!=-1) { return pMenuIcon; } } } } else { m_pSharedMenuIcons = new CTypedPtrList<CPtrList, CSkinMenuIcons*>; } CSkinMenuBitmaps* pMenuIcon = new CSkinMenuBitmaps(); pMenuIcon->m_crTransparent = m_bitmapBackground; nIndex = pMenuIcon->Add(pBmp,m_bitmapBackground); if(nIndex!=-1) { m_pSharedMenuIcons->AddTail(pMenuIcon); return pMenuIcon; } delete pMenuIcon; return NULL; } CSkinMenuIcons* CSkinMenu::GetToolbarIcons(UINT nToolBar, HMODULE hInst) { ASSERT_VALID(this); ASSERT(nToolBar != NULL); if(m_pSharedMenuIcons!=NULL) { POSITION pos = m_pSharedMenuIcons->GetHeadPosition(); while(pos) { CSkinMenuIcons* pMenuIcon = m_pSharedMenuIcons->GetNext(pos); if(pMenuIcon->DoMatch(MAKEINTRESOURCE(nToolBar),hInst)) { return pMenuIcon; } } } else { m_pSharedMenuIcons = new CTypedPtrList<CPtrList, CSkinMenuIcons*>; } CSkinMenuIcons* pMenuIcon = new CSkinMenuIcons(); pMenuIcon->m_crTransparent = m_bitmapBackground; if(pMenuIcon->LoadToolBar(MAKEINTRESOURCE(nToolBar),hInst)) { m_pSharedMenuIcons->AddTail(pMenuIcon); return pMenuIcon; } delete pMenuIcon; return NULL; } BOOL CSkinMenu::LoadToolBar(LPCTSTR lpszResourceName, HMODULE hInst) { CSkinMenuIcons* pMenuIcon = GetToolbarIcons((UINT)(UINT_PTR)lpszResourceName,hInst); if(pMenuIcon) { SetMenuIcons(pMenuIcon); return TRUE; } return FALSE; } BOOL CSkinMenu::LoadToolBar(HBITMAP hBitmap, CSize size, UINT* pID, COLORREF crTransparent) { ASSERT_VALID(this); ASSERT(pID); if(crTransparent==CLR_NONE) { crTransparent = m_bitmapBackground; } if(m_pSharedMenuIcons!=NULL) { POSITION pos = m_pSharedMenuIcons->GetHeadPosition(); while(pos) { CSkinMenuIcons* pMenuIcon = m_pSharedMenuIcons->GetNext(pos); if(pMenuIcon->DoMatch(hBitmap,size,pID)) { SetMenuIcons(pMenuIcon); return TRUE; } } } else { m_pSharedMenuIcons = new CTypedPtrList<CPtrList, CSkinMenuIcons*>; } CSkinMenuIcons* pMenuIcon = new CSkinMenuIcons(); if(pMenuIcon->LoadToolBar(hBitmap,size,pID,crTransparent)) { m_pSharedMenuIcons->AddTail(pMenuIcon); SetMenuIcons(pMenuIcon); return TRUE; } delete pMenuIcon; return FALSE; } BOOL CSkinMenu::LoadToolBar(WORD* pToolInfo, COLORREF crTransparent) { ASSERT_VALID(this); ASSERT(pToolInfo); if(crTransparent==CLR_NONE) { crTransparent = m_bitmapBackground; } if(m_pSharedMenuIcons!=NULL) { POSITION pos = m_pSharedMenuIcons->GetHeadPosition(); while(pos) { CSkinMenuIcons* pMenuIcon = m_pSharedMenuIcons->GetNext(pos); if(pMenuIcon->DoMatch(pToolInfo,crTransparent)) { SetMenuIcons(pMenuIcon); return TRUE; } } } else { m_pSharedMenuIcons = new CTypedPtrList<CPtrList, CSkinMenuIcons*>; } CSkinMenuIcons* pMenuIcon = new CSkinMenuIcons(); if(pMenuIcon->LoadToolBar(pToolInfo,crTransparent)) { m_pSharedMenuIcons->AddTail(pMenuIcon); SetMenuIcons(pMenuIcon); return TRUE; } delete pMenuIcon; return FALSE; } // Jan-12-2005 - Mark P. Peterson - mpp@rhinosoft.com - http://www.RhinoSoft.com/ // added this function as a helper to LoadToolBar(WORD* pToolInfo, COLORREF crTransparent), the purpose of this function // is to easily load a high color toolbar to the menu, instead of creating and maintaining a command map. this function // simply reads an existing 16 bit toolbar, and builds the word map based on that toolbar, using the 256 color bitmap. BOOL CSkinMenu::LoadToolBar(UINT n16ToolBarID, UINT n256BitmapID, COLORREF transparentColor, HMODULE hInst) { BOOL bRet = FALSE; // determine location of the bitmap in resource if(hInst==0) { hInst = AfxFindResourceHandle(MAKEINTRESOURCE(n16ToolBarID), RT_TOOLBAR); } HRSRC hRsrc = ::FindResource(hInst, MAKEINTRESOURCE(n16ToolBarID), RT_TOOLBAR); if (hRsrc == NULL) { // Special purpose when you try to load it from a dll 30.05.2002 if(AfxGetResourceHandle()!=hInst) { hInst = AfxGetResourceHandle(); hRsrc = ::FindResource(hInst, MAKEINTRESOURCE(n16ToolBarID), RT_TOOLBAR); } if (hRsrc == NULL) { return FALSE; } } HGLOBAL hGlobal = LoadResource(hInst, hRsrc); if (hGlobal) { CToolBarData* pData = (CToolBarData*)LockResource(hGlobal); if (pData) { int nSize = sizeof(WORD)*(pData->wItemCount+4); // no need for delete WORD* pToolId = (WORD*)_alloca(nSize); // sets also the last entry to zero ZeroMemory(pToolId,nSize); pToolId[0] = (WORD)n256BitmapID; pToolId[1] = pData->wWidth; pToolId[2] = pData->wHeight; WORD* pTemp = pToolId+3; for (int nIndex = 0; nIndex < pData->wItemCount; nIndex++) { // not a seperator? if( (pData->items()[nIndex]) ) { *pTemp++ = pData->items()[nIndex]; } } // load the toolbar images into the menu bRet = LoadToolBar(pToolId, transparentColor); UnlockResource(hGlobal); } FreeResource(hGlobal); } // return TRUE for success, FALSE for failure return (bRet); } // LoadHiColor BOOL CSkinMenu::LoadToolBar(UINT nToolBar, HMODULE hInst) { return LoadToolBar((LPCTSTR)(UINT_PTR)nToolBar,hInst); } BOOL CSkinMenu::LoadFromToolBar(UINT nID, UINT nToolBar, int& xoffset) { int xset,offset; UINT nStyle; BOOL returnflag=FALSE; CToolBar bar; CWnd* pWnd = AfxGetMainWnd(); if (pWnd == NULL) pWnd = CWnd::GetDesktopWindow(); bar.Create(pWnd); if(bar.LoadToolBar(nToolBar)) { offset=bar.CommandToIndex(nID); if(offset>=0) { bar.GetButtonInfo(offset,nID,nStyle,xset); if(xset>0) xoffset = xset; returnflag=TRUE; } } return returnflag; } // O.S. CSkinMenuItemData* CSkinMenu::FindMenuItem(UINT nID) { CSkinMenuItemData *pData = NULL; int i; for(i = 0; i < m_MenuItemList.GetSize(); i++) { if (m_MenuItemList[i]->m_nID == nID) { pData = m_MenuItemList[i]; break; } } if (!pData) { int loc; CSkinMenu *pMenu = FindMenuOption(nID, loc); ASSERT(pMenu != this); if (loc >= 0) { return pMenu->FindMenuItem(nID); } } return pData; } CSkinMenu* CSkinMenu::FindAnotherMenuOption(int nId, int& nLoc, CArray<CSkinMenu*,CSkinMenu*>&newSubs, CArray<int,int&>&newLocs) { int i,numsubs,j; CSkinMenu *pSubMenu,*pgoodmenu; BOOL foundflag; for(i=0;i<(int)(GetMenuItemCount());++i) { pSubMenu = DYNAMIC_DOWNCAST(CSkinMenu,GetSubMenu(i)); if(pSubMenu) { pgoodmenu = pSubMenu->FindAnotherMenuOption(nId,nLoc,newSubs,newLocs); if(pgoodmenu) { return pgoodmenu; } } else if(nId==(int)GetMenuItemID(i)) { numsubs = (int)newSubs.GetSize(); foundflag = TRUE; for(j=0;j<numsubs;++j) { if(newSubs[j]==this && newLocs[j]==i) { foundflag = FALSE; break; } } if(foundflag) { nLoc = i; return this; } } } nLoc = -1; return NULL; } CSkinMenu* CSkinMenu::FindMenuOption(int nId, int& nLoc) { int i; CSkinMenu *pSubMenu,*pgoodmenu; for(i=0;i<(int)(GetMenuItemCount());++i) { pSubMenu = DYNAMIC_DOWNCAST(CSkinMenu,GetSubMenu(i)); if(pSubMenu) { pgoodmenu = pSubMenu->FindMenuOption(nId,nLoc); if(pgoodmenu) { return pgoodmenu; } } else if(nId==(int)GetMenuItemID(i)) { nLoc = i; return(this); } } nLoc = -1; return NULL; } CSkinMenu* CSkinMenu::FindMenuOption(LPCTSTR lpstrText, int& nLoc) { int i; // First look for all item text. for(i=0;i<(int)m_MenuItemList.GetSize();++i) { if(m_MenuItemList[i]->m_szMenuText.Compare(lpstrText)==NULL) { nLoc = i; return this; } } CSkinMenu* pSubMenu; // next, look in all submenus for(i=0; i<(int)(GetMenuItemCount());++i) { pSubMenu = DYNAMIC_DOWNCAST(CSkinMenu,GetSubMenu(i)); if(pSubMenu) { pSubMenu = pSubMenu->FindMenuOption(lpstrText,nLoc); if(pSubMenu) { return pSubMenu; } } } nLoc = -1; return NULL; } BOOL CSkinMenu::LoadMenu(HMENU hMenu) { if(!::IsMenu(hMenu) || !Attach(hMenu)) { return FALSE; } m_bIsPopupMenu = FALSE; for(int i=0;i<(int)(GetMenuItemCount());++i) { HMENU hSubMenu = ::GetSubMenu(m_hMenu,i); if(hSubMenu) { CSkinMenu* pMenu = new CSkinMenu(m_hMenu); m_SubMenus.Add(hSubMenu); pMenu->LoadMenu(hSubMenu); pMenu->m_bIsPopupMenu = TRUE; } } SynchronizeMenu(); return TRUE; } BOOL CSkinMenu::LoadMenu(int nResource) { return(CSkinMenu::LoadMenu(MAKEINTRESOURCE(nResource))); } BOOL CSkinMenu::LoadMenu(LPCTSTR lpszResourceName) { ASSERT(this); HMENU hMenu = ::LoadMenu(AfxFindResourceHandle(lpszResourceName,RT_MENU), lpszResourceName); #ifdef _DEBUG ShowLastError(_T("Error from Menu: LoadMenu")); #endif return LoadMenu(hMenu); } BOOL CSkinMenu::SetItemData(UINT uiId, DWORD_PTR dwItemData, BOOL fByPos) { MENUITEMINFO MenuItemInfo = {0}; MenuItemInfo.cbSize = sizeof(MenuItemInfo); MenuItemInfo.fMask = MIIM_DATA; if(::GetMenuItemInfo(m_hMenu,uiId,fByPos,&MenuItemInfo)) { CSkinMenuItemData* pItem = CheckMenuItemData(MenuItemInfo.dwItemData); if(pItem) { pItem->m_pData = (void*)dwItemData; return TRUE; } } return FALSE; } BOOL CSkinMenu::SetItemDataPtr(UINT uiId, void* pItemData, BOOL fByPos ) { return SetItemData(uiId, (DWORD_PTR) pItemData, fByPos); } DWORD_PTR CSkinMenu::GetItemData(UINT uiId, BOOL fByPos) const { MENUITEMINFO MenuItemInfo = {0}; MenuItemInfo.cbSize = sizeof(MenuItemInfo); MenuItemInfo.fMask = MIIM_DATA; if(::GetMenuItemInfo(m_hMenu,uiId,fByPos,&MenuItemInfo)) { CSkinMenuItemData* pItem = CheckMenuItemData(MenuItemInfo.dwItemData); if(pItem) { return (DWORD_PTR)pItem->m_pData; } } return DWORD_PTR(-1); } void* CSkinMenu::GetItemDataPtr(UINT uiId, BOOL fByPos) const { return (void*)GetItemData(uiId,fByPos); } BOOL CSkinMenu::SetMenuData(DWORD_PTR dwMenuData) { m_pData = (void*)dwMenuData; return TRUE; } BOOL CSkinMenu::SetMenuDataPtr(void* pMenuData) { m_pData = (void*)pMenuData; return TRUE; } DWORD_PTR CSkinMenu::GetMenuData() const { return (DWORD_PTR)m_pData; } void* CSkinMenu::GetMenuDataPtr() const { return m_pData; } BOOL CSkinMenu::m_bDrawAccelerators = TRUE; BOOL CSkinMenu::SetAcceleratorsDraw (BOOL bDraw) { BOOL bOld = m_bDrawAccelerators; m_bDrawAccelerators = bDraw; return bOld; } BOOL CSkinMenu::GetAcceleratorsDraw() { return m_bDrawAccelerators; } BYTE CSkinMenu::m_bAlpha = 255; BYTE CSkinMenu::SetAlpha(BYTE bAlpha) { BYTE oldAlpha = m_bAlpha; m_bAlpha = bAlpha; return oldAlpha; } BYTE CSkinMenu::GetAlpha() { return m_bAlpha; } // INVALID_HANDLE_VALUE = Draw default frame's accel. NULL = Off HACCEL CSkinMenu::SetAccelerator (HACCEL hAccel) { HACCEL hOld = m_hAccelToDraw; m_hAccelToDraw = hAccel; return hOld; } HACCEL CSkinMenu::GetAccelerator () { return m_hAccelToDraw; } void CSkinMenu::LoadCheckmarkBitmap(int unselect, int select) { if(unselect>0 && select>0) { m_selectcheck = select; m_unselectcheck = unselect; if(m_checkmaps) m_checkmaps->DeleteImageList(); else m_checkmaps = new CImageList(); m_checkmaps->Create(m_iconX,m_iconY,ILC_MASK,2,1); BOOL flag1 = AddBitmapToImageList(m_checkmaps,unselect); BOOL flag2 = AddBitmapToImageList(m_checkmaps,select); if(!flag1||!flag2) { m_checkmaps->DeleteImageList(); delete m_checkmaps; m_checkmaps = NULL; } } } BOOL CSkinMenu::GetMenuText(UINT id, CString& string, UINT nFlags/*= MF_BYPOSITION*/) { if(MF_BYPOSITION&nFlags) { UINT numMenuItems = (int)m_MenuItemList.GetSize(); if(id<numMenuItems) { string = m_MenuItemList[id]->GetString(m_bDrawAccelerators ? m_hAccelToDraw : NULL); return TRUE; } } else { int uiLoc; CSkinMenu* pMenu = FindMenuOption(id,uiLoc); if(NULL!=pMenu) { return pMenu->GetMenuText(uiLoc,string); } } return FALSE; } CSkinMenuItemData* CSkinMenu::CheckMenuItemData(ULONG_PTR nItemData) const { for(int i=0;i<m_MenuItemList.GetSize();++i) { CSkinMenuItemData* pItem = m_MenuItemList[i]; if ( ((ULONG_PTR)pItem)==nItemData ) { return pItem; } } return NULL; } CSkinMenuItemData* CSkinMenu::FindMenuList(UINT nID) { for(int i=0;i<m_MenuItemList.GetSize();++i) { CSkinMenuItemData* pMenuItem = m_MenuItemList[i]; if(pMenuItem->m_nID==nID && !pMenuItem->m_nSyncFlag) { pMenuItem->m_nSyncFlag = 1; return pMenuItem; } } return NULL; } void CSkinMenu::InitializeMenuList(int value) { for(int i=0;i<m_MenuItemList.GetSize();++i) { m_MenuItemList[i]->m_nSyncFlag = value; } } void CSkinMenu::DeleteMenuList() { for(int i=0;i<m_MenuItemList.GetSize();++i) { if(!m_MenuItemList[i]->m_nSyncFlag) { delete m_MenuItemList[i]; } } } void CSkinMenu::SynchronizeMenu() { CTypedPtrArray<CPtrArray, CSkinMenuItemData*> temp; CSkinMenuItemData *pItemData; CString string; UINT submenu,state,j; InitializeMenuList(0); for(j=0;j<GetMenuItemCount();++j) { MENUITEMINFO menuInfo = {0}; menuInfo.cbSize = sizeof(menuInfo); // we get a wrong state for seperators menuInfo.fMask = MIIM_TYPE|MIIM_ID|MIIM_STATE; // item doesn't exist if(!GetMenuItemInfo(j,&menuInfo,TRUE)) { break; } state = GetMenuState(j,MF_BYPOSITION); if(state!=menuInfo.fState) { state|=0; } pItemData=NULL; if(state==UINT_PTR(-1)) { break; } if(!(state&MF_SYSMENU)) { if(menuInfo.fType&MFT_RIGHTJUSTIFY) { state |= MF_RIGHTJUSTIFY; } // MFT_RIGHTORDER is the same value as MFT_SYSMENU. // We distinguish between the two by also looking for MFT_BITMAP. if(!(state&MF_BITMAP) && (menuInfo.fType&MFT_RIGHTORDER) ) { state |= MFT_RIGHTORDER; } } // Special purpose for Windows NT 4.0 if(state&MF_BITMAP) { // Bitmap-button like system menu, maximize, minimize and close // just ignore. UINT nID = GetMenuItemID(j); pItemData = FindMenuList(nID); if(!pItemData) { pItemData = new CSkinMenuItemData; pItemData->m_nFlags = state; pItemData->m_nID = nID; } } else if(state&MF_POPUP) { HMENU hSubMenu = GetSubMenu(j)->m_hMenu; submenu = (UINT)hSubMenu; pItemData = FindMenuList(submenu); GetMenuString(j,string,MF_BYPOSITION); if(!pItemData) { state &= ~(MF_USECHECKBITMAPS|MF_SEPARATOR); pItemData = NewODMenu(j,state|MF_BYPOSITION|MF_POPUP|MF_OWNERDRAW,submenu,string); } else if(!string.IsEmpty ()) { pItemData->SetString(string); } CSkinMenu* pSubMenu = DYNAMIC_DOWNCAST(CSkinMenu,CMenu::FromHandlePermanent(hSubMenu)); if(pSubMenu && pSubMenu->m_hParentMenu!=m_hMenu) { // Sets again the parent to this one pSubMenu->m_hParentMenu = m_hMenu; } } else if(state&MF_SEPARATOR) { pItemData = FindMenuList(0); if(!pItemData) { pItemData = NewODMenu(j,state|MF_BYPOSITION|MF_OWNERDRAW,0,_T("")); } else { pItemData->m_nFlags = state|MF_BYPOSITION|MF_OWNERDRAW; ModifyMenu(j,pItemData->m_nFlags,0,(LPCTSTR)pItemData); } } else { UINT nID = GetMenuItemID(j); pItemData = FindMenuList(nID); GetMenuString(j,string,MF_BYPOSITION); if(!pItemData) { pItemData = NewODMenu(j,state|MF_BYPOSITION|MF_OWNERDRAW,nID,string); } else { pItemData->m_nFlags = state|MF_BYPOSITION|MF_OWNERDRAW; if(string.GetLength()>0) pItemData->SetString(string); ModifyMenu(j,pItemData->m_nFlags,nID,(LPCTSTR)pItemData); } } if(pItemData) temp.Add(pItemData); } DeleteMenuList(); m_MenuItemList.RemoveAll(); m_MenuItemList.Append(temp); temp.RemoveAll(); } void CSkinMenu::OnInitMenuPopup(HWND hWnd, CMenu* pPopupMenu, UINT nIndex, BOOL bSysMenu) { UNREFERENCED_PARAMETER(nIndex); UNREFERENCED_PARAMETER(bSysMenu); CSkinMenuHook::m_hLastMenu = pPopupMenu->m_hMenu; if(IsMenu(pPopupMenu->m_hMenu)) { CSkinMenu* pSubMenu = DYNAMIC_DOWNCAST(CSkinMenu,pPopupMenu); if(pSubMenu) { pSubMenu->m_hTempOwner = hWnd; pSubMenu->OnInitMenuPopup(); HMENU hMenu = pSubMenu->GetParent(); CSkinMenu* pParent = DYNAMIC_DOWNCAST(CSkinMenu,CMenu::FromHandlePermanent(hMenu)); if(pParent) { pParent->m_dwOpenMenu += 1; if(pParent->m_dwOpenMenu==1 && !pParent->m_bIsPopupMenu) { // Redraw the menubar for the shade CRect rect = pParent->GetLastActiveMenuRect(); if(!rect.IsRectEmpty()) { rect.InflateRect(0,0,10,10); CPoint Point(0,0); ClientToScreen(hWnd,&Point); rect.OffsetRect(-Point); RedrawWindow(hWnd,rect,0,RDW_FRAME|RDW_INVALIDATE); } } } } } } BOOL CSkinMenu::Replace(UINT nID, UINT nNewID) { int nLoc=0; CSkinMenu* pTempMenu = FindMenuOption(nID,nLoc); if(pTempMenu && nLoc >= 0) { CSkinMenuItemData* pData = pTempMenu->m_MenuItemList[nLoc]; UINT nFlags = pData->m_nFlags|MF_OWNERDRAW|MF_BYPOSITION; pData->m_nID = nNewID; return pTempMenu->ModifyMenu(nLoc,nFlags,nNewID,(LPCTSTR)pData); } return FALSE; } void CSkinMenu::OnInitMenuPopup() { m_bIsPopupMenu = true; SynchronizeMenu(); // Special purpose for windows XP with themes!!! if(g_Shell==WinXP) { Replace(SC_RESTORE,SC_RESTORE+1); Replace(SC_CLOSE,SC_CLOSE+1); Replace(SC_MINIMIZE,SC_MINIMIZE+1); } } BOOL CSkinMenu::OnUnInitPopupMenu() { if(g_Shell==WinXP) { // Special purpose for windows XP with themes!!! // Restore old values otherwise you have disabled windowbuttons Replace(SC_MINIMIZE+1,SC_MINIMIZE); Replace(SC_RESTORE+1,SC_RESTORE); if(Replace(SC_CLOSE+1,SC_CLOSE)) { //EnableMenuItem(SC_CLOSE, MF_BYCOMMAND|MF_ENABLED); SetWindowPos(m_hTempOwner,0,0,0,0,0,SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOSIZE|SWP_NOZORDER); } //Replace(SC_RESTORE+1,SC_RESTORE); //Replace(SC_MINIMIZE+1,SC_MINIMIZE); } HMENU hMenu = GetParent(); CSkinMenu* pParent = DYNAMIC_DOWNCAST(CSkinMenu,CMenu::FromHandlePermanent(hMenu)); if(pParent) { pParent->m_dwOpenMenu -= 1; if(pParent->m_dwOpenMenu>=NULL && !pParent->m_bIsPopupMenu) { pParent->m_dwOpenMenu = 0; // Redraw the menubar for the shade CRect rect = pParent->GetLastActiveMenuRect(); if(!rect.IsRectEmpty()) { rect.InflateRect(0,0,10,10); CPoint Point(0,0); ClientToScreen(m_hTempOwner,&Point); rect.OffsetRect(-Point); RedrawWindow(m_hTempOwner,rect,0,RDW_FRAME|RDW_INVALIDATE); } return TRUE; } } return FALSE; } LRESULT CSkinMenu::FindKeyboardShortcut(UINT nChar, UINT nFlags, CMenu* pMenu) { UNREFERENCED_PARAMETER(nFlags); CSkinMenu* pNewMenu = DYNAMIC_DOWNCAST(CSkinMenu,pMenu); if(pNewMenu) { //SK: modified for Unicode correctness CString key(_T('&'),2); key.SetAt(1,(TCHAR)nChar); key.MakeLower(); CString menutext; int menusize = (int)pNewMenu->GetMenuItemCount(); if(menusize!=(pNewMenu->m_MenuItemList.GetSize())) pNewMenu->SynchronizeMenu(); for(int i=0;i<menusize;++i) { if(pNewMenu->GetMenuText(i,menutext)) { menutext.MakeLower(); if(menutext.Find(key)>=0) { return(MAKELRESULT(i,2)); } } } } return NULL; } BOOL CSkinMenu::AddBitmapToImageList(CImageList* bmplist,UINT nResourceID) { // O.S. if (m_bDynIcons) { bmplist->Add((HICON)(UINT_PTR)nResourceID); return TRUE; } CBitmap mybmp; HBITMAP hbmp = LoadSysColorBitmap(nResourceID); if(hbmp) // Object will be destroyd by destructor of CBitmap mybmp.Attach(hbmp); else mybmp.LoadBitmap(nResourceID); if (mybmp.m_hObject && bmplist->Add(&mybmp,GetBitmapBackground())>=0 ) return TRUE; return FALSE; } COLORREF CSkinMenu::SetBitmapBackground(COLORREF newColor) { COLORREF oldColor = m_bitmapBackground; m_bitmapBackground = newColor; return oldColor; } COLORREF CSkinMenu::GetBitmapBackground() { if(m_bitmapBackground==CLR_DEFAULT) return GetSysColor(COLOR_3DFACE); return m_bitmapBackground; } HBITMAP CSkinMenu::LoadSysColorBitmap(int nResourceId) { HINSTANCE hInst = AfxFindResourceHandle(MAKEINTRESOURCE(nResourceId),RT_BITMAP); HRSRC hRsrc = ::FindResource(hInst,MAKEINTRESOURCE(nResourceId),RT_BITMAP); if (hRsrc == NULL) return NULL; // determine how many colors in the bitmap HGLOBAL hglb; if ((hglb = LoadResource(hInst, hRsrc)) == NULL) return NULL; LPBITMAPINFOHEADER lpBitmap = (LPBITMAPINFOHEADER)LockResource(hglb); if (lpBitmap == NULL) { return NULL; } WORD numcol = NumBitmapColors(lpBitmap); ::FreeResource(hglb); if(numcol!=16) return(NULL); return AfxLoadSysColorBitmap(hInst, hRsrc, FALSE); } // sPos means Seperator's position, since we have no way to find the // seperator's position in the menu we have to specify them when we call the // RemoveMenu to make sure the unused seperators are removed; // sPos = None no seperator removal; // = Head seperator in front of this menu item; // = Tail seperator right after this menu item; // = Both seperators at both ends; // remove the menu item based on their text, return -1 if not found, otherwise // return the menu position; int CSkinMenu::RemoveMenu(LPCTSTR pText, ESeperator sPos) { int nPos = GetMenuPosition(pText); if(nPos != -1) { switch (sPos) { case CSkinMenu::NONE: RemoveMenu(nPos, MF_BYPOSITION); break; case CSkinMenu::HEAD: ASSERT(nPos - 1 >= 0); RemoveMenu(nPos-1, MF_BYPOSITION); break; case CSkinMenu::TAIL: RemoveMenu(nPos+1, MF_BYPOSITION); break; case CSkinMenu::BOTH: // remove the end first; RemoveMenu(nPos+1, MF_BYPOSITION); // remove the head; ASSERT(nPos - 1 >= 0); RemoveMenu(nPos-1, MF_BYPOSITION); break; } } return nPos; } BOOL CSkinMenu::RemoveMenu(UINT uiId, UINT nFlags) { if(MF_BYPOSITION&nFlags) { UINT nItemState = GetMenuState(uiId,MF_BYPOSITION); if((nItemState&MF_SEPARATOR) && !(nItemState&MF_POPUP)) { CSkinMenuItemData* pData = m_MenuItemList.GetAt(uiId); m_MenuItemList.RemoveAt(uiId); delete pData; } else { CMenu* pSubMenu = GetSubMenu(uiId); if(NULL==pSubMenu) { UINT uiCommandId = GetMenuItemID(uiId); for(int i=0;i<m_MenuItemList.GetSize(); i++) { if(m_MenuItemList[i]->m_nID==uiCommandId) { CSkinMenuItemData* pData = m_MenuItemList.GetAt(i); m_MenuItemList.RemoveAt(i); delete pData; break; } } } else { // Only remove the menu. int numSubMenus = (int)m_SubMenus.GetSize(); while(numSubMenus--) { if(m_SubMenus[numSubMenus]==pSubMenu->m_hMenu) { m_SubMenus.RemoveAt(numSubMenus); } } numSubMenus = (int)m_MenuItemList.GetSize(); while(numSubMenus--) { if(m_MenuItemList[numSubMenus]->m_nID==(UINT)pSubMenu->m_hMenu ) { CSkinMenuItemData* pData = m_MenuItemList.GetAt(numSubMenus); m_MenuItemList.RemoveAt(numSubMenus); delete pData; break; } } // Don't delete it's only remove //delete pSubMenu; } } } else { int iPosition =0; CSkinMenu* pMenu = FindMenuOption(uiId,iPosition); if(pMenu) return pMenu->RemoveMenu(iPosition,MF_BYPOSITION); } return CMenu::RemoveMenu(uiId,nFlags); } BOOL CSkinMenu::DeleteMenu(UINT uiId, UINT nFlags) { if(MF_BYPOSITION&nFlags) { UINT nItemState = GetMenuState(uiId,MF_BYPOSITION); if( (nItemState&MF_SEPARATOR) && !(nItemState&MF_POPUP)) { CSkinMenuItemData* pData = m_MenuItemList.GetAt(uiId); m_MenuItemList.RemoveAt(uiId); delete pData; } else { CMenu* pSubMenu = GetSubMenu(uiId); if(NULL==pSubMenu) { UINT uiCommandId = GetMenuItemID(uiId); for(int i=0;i<m_MenuItemList.GetSize(); i++) { if(m_MenuItemList[i]->m_nID==uiCommandId) { CSkinMenuItemData* pData = m_MenuItemList.GetAt(i); m_MenuItemList.RemoveAt(i); delete pData; } } } else { BOOL bCanDelete = FALSE; int numSubMenus = (int)m_SubMenus.GetSize(); while(numSubMenus--) { if(m_SubMenus[numSubMenus]==pSubMenu->m_hMenu) { m_SubMenus.RemoveAt(numSubMenus); bCanDelete = TRUE; } } numSubMenus = (int)m_MenuItemList.GetSize(); while(numSubMenus--) { if(m_MenuItemList[numSubMenus]->m_nID==(UINT)pSubMenu->m_hMenu ) { CSkinMenuItemData* pData = m_MenuItemList.GetAt(numSubMenus); m_MenuItemList.RemoveAt(numSubMenus); delete pData; break; } } // Did we created the menu if(bCanDelete) { // Oh yes so we can destroy it delete pSubMenu; } } } } else { int iPosition =0; CSkinMenu* pMenu = FindMenuOption(uiId,iPosition); if(pMenu) return pMenu->DeleteMenu(iPosition,MF_BYPOSITION); } return CMenu::DeleteMenu(uiId,nFlags); } BOOL CSkinMenu::AppendMenu(UINT nFlags, UINT nIDNewItem, LPCTSTR lpszNewItem, int nIconNormal) { return AppendODMenu(lpszNewItem,nFlags,nIDNewItem,nIconNormal); } BOOL CSkinMenu::AppendMenu(UINT nFlags, UINT nIDNewItem, LPCTSTR lpszNewItem, CImageList* il, int xoffset) { return AppendODMenu(lpszNewItem,nFlags,nIDNewItem,il,xoffset); } BOOL CSkinMenu::AppendMenu(UINT nFlags, UINT nIDNewItem, LPCTSTR lpszNewItem, CBitmap* bmp) { return AppendODMenu(lpszNewItem,nFlags,nIDNewItem,bmp); } BOOL CSkinMenu::InsertMenu(UINT nPosition, UINT nFlags, UINT nIDNewItem, LPCTSTR lpszNewItem, int nIconNormal) { return InsertODMenu(nPosition,lpszNewItem,nFlags,nIDNewItem,nIconNormal); } BOOL CSkinMenu::InsertMenu(UINT nPosition, UINT nFlags, UINT nIDNewItem, LPCTSTR lpszNewItem, CImageList* il, int xoffset) { return InsertODMenu(nPosition,lpszNewItem,nFlags,nIDNewItem,il,xoffset); } BOOL CSkinMenu::InsertMenu(UINT nPosition, UINT nFlags, UINT nIDNewItem, LPCTSTR lpszNewItem, CBitmap* bmp) { return InsertODMenu(nPosition,lpszNewItem,nFlags,nIDNewItem,bmp); } CSkinMenu* CSkinMenu::AppendODPopupMenu(LPCTSTR lpstrText) { CSkinMenu* pSubMenu = new CSkinMenu(m_hMenu); pSubMenu->m_unselectcheck=m_unselectcheck; pSubMenu->m_selectcheck=m_selectcheck; pSubMenu->m_checkmaps=m_checkmaps; pSubMenu->m_checkmapsshare=TRUE; pSubMenu->CreatePopupMenu(); if(AppendODMenu(lpstrText,MF_POPUP,(UINT)pSubMenu->m_hMenu, -1)) { m_SubMenus.Add(pSubMenu->m_hMenu); return pSubMenu; } delete pSubMenu; return NULL; } CMenu* CSkinMenu::GetSubMenu(int nPos) const { return CMenu::GetSubMenu (nPos); } CMenu* CSkinMenu::GetSubMenu(LPCTSTR lpszSubMenuName) const { int num = GetMenuItemCount (); CString name; MENUITEMINFO info = {0}; for (int i=0; i<num; i++) { GetMenuString (i, name, MF_BYPOSITION); // fix from George Menhorn if(name.IsEmpty()) { info.cbSize = sizeof (MENUITEMINFO); info.fMask = MIIM_DATA; ::GetMenuItemInfo(m_hMenu, i, TRUE, &info); CSkinMenuItemData* pItemData = CheckMenuItemData(info.dwItemData); if (pItemData) name = pItemData->GetString(m_bDrawAccelerators ? m_hAccelToDraw : NULL); } if (name.Compare (lpszSubMenuName) == 0) return CMenu::GetSubMenu (i); } return NULL; } // Tongzhe Cui, Functions to remove a popup menu based on its name. Seperators // before and after the popup menu can also be removed if they exist. int CSkinMenu::GetMenuPosition(LPCTSTR pText) { for(int i=0;i<(int)(GetMenuItemCount());++i) { if(!GetSubMenu(i)) { for(int j=0;j<m_MenuItemList.GetSize();++j) { if(m_MenuItemList[j]->m_szMenuText.Compare(pText)==NULL) return j; } } } // means no found; return -1; } BOOL CSkinMenu::RemoveMenuTitle() { int numMenuItems = (int)m_MenuItemList.GetSize(); // We need a seperator at the beginning of the menu if(!numMenuItems || !((m_MenuItemList[0]->m_nFlags)&MF_SEPARATOR) ) return FALSE; CSkinMenuItemData* pMenuData = m_MenuItemList[0]; // Check for title if(pMenuData->m_nTitleFlags&MFT_TITLE) { if(numMenuItems>0) { CSkinMenuItemData* pMenuNextData = m_MenuItemList[1]; if((pMenuNextData->m_nFlags&MF_MENUBREAK)) { pMenuNextData->m_nFlags &= ~MF_MENUBREAK; CMenu::ModifyMenu(1,MF_BYPOSITION|pMenuNextData->m_nFlags,pMenuNextData->m_nID,(LPCTSTR)pMenuNextData); } } // Now remove the title RemoveMenu(0,MF_BYPOSITION); return TRUE; } return FALSE; } BOOL CSkinMenu::SetMenuTitle(LPCTSTR pTitle, UINT nTitleFlags, int nIconNormal) { int nIndex = -1; CSkinMenuIconLock iconLock(GetMenuIcon(nIndex,nIconNormal)); return SetMenuTitle(pTitle,nTitleFlags,iconLock,nIndex); } BOOL CSkinMenu::SetMenuTitle(LPCTSTR pTitle, UINT nTitleFlags, CBitmap* pBmp) { int nIndex = -1; CSkinMenuIconLock iconLock(GetMenuIcon(nIndex,pBmp)); return SetMenuTitle(pTitle,nTitleFlags,iconLock,nIndex); } BOOL CSkinMenu::SetMenuTitle(LPCTSTR pTitle, UINT nTitleFlags, CImageList *pil, int xoffset) { int nIndex = -1; CSkinMenuIconLock iconLock(GetMenuIcon(nIndex,0,pil,xoffset)); return SetMenuTitle(pTitle,nTitleFlags,iconLock,nIndex); } BOOL CSkinMenu::SetMenuTitle(LPCTSTR pTitle, UINT nTitleFlags, CSkinMenuIcons* pIcons, int nIndex) { return TRUE; // 不使用 // Check if menu is valid if(!::IsMenu(m_hMenu)) return FALSE; // Check the menu integrity if((int)GetMenuItemCount()!=(int)m_MenuItemList.GetSize()) SynchronizeMenu(); int numMenuItems = (int)m_MenuItemList.GetSize(); // We need a seperator at the beginning of the menu if(!numMenuItems || !((m_MenuItemList[0]->m_nFlags)&MF_SEPARATOR) ) { // We add the special menu item for title CSkinMenuItemData *pItemData = new CSkinMenuItemDataTitle; m_MenuItemList.InsertAt(0,pItemData); pItemData->SetString(pTitle); pItemData->m_nFlags = MF_BYPOSITION|MF_SEPARATOR|MF_OWNERDRAW; VERIFY(CMenu::InsertMenu(0,MF_SEPARATOR|MF_BYPOSITION,0,pItemData->m_szMenuText)); VERIFY(CMenu::ModifyMenu(0, MF_BYPOSITION|MF_SEPARATOR|MF_OWNERDRAW, 0, (LPCTSTR)pItemData )); //InsertMenu(0,MF_SEPARATOR|MF_BYPOSITION); } numMenuItems = (int)m_MenuItemList.GetSize(); if(numMenuItems) { CSkinMenuItemData* pMenuData = m_MenuItemList[0]; if(pMenuData->m_nFlags&MF_SEPARATOR) { pIcons->AddRef(); pMenuData->m_pMenuIcon->Release(); pMenuData->m_pMenuIcon = pIcons; if(pIcons && nIndex>=0) { pMenuData->m_nMenuIconOffset = nIndex; //CSize size = pIcons->GetIconSize(); //m_iconX = max(m_iconX,size.cx); //m_iconY = max(m_iconY,size.cy); } else pMenuData->m_nMenuIconOffset = -1; pMenuData->SetString(pTitle); pMenuData->m_nTitleFlags = nTitleFlags|MFT_TITLE; if(numMenuItems>1) { CSkinMenuItemData* pMenuData = m_MenuItemList[1]; if(nTitleFlags&MFT_SIDE_TITLE) { if(!(pMenuData->m_nFlags&MF_MENUBREAK)) { pMenuData->m_nFlags |= MF_MENUBREAK; CMenu::ModifyMenu(1,MF_BYPOSITION|pMenuData->m_nFlags,pMenuData->m_nID,(LPCTSTR)pMenuData); } } else { if((pMenuData->m_nFlags&MF_MENUBREAK)) { pMenuData->m_nFlags &= ~MF_MENUBREAK; CMenu::ModifyMenu(1,MF_BYPOSITION|pMenuData->m_nFlags,pMenuData->m_nID,(LPCTSTR)pMenuData); } } return TRUE; } } } return FALSE; } CSkinMenuItemDataTitle* CSkinMenu::GetMemuItemDataTitle() { // Check if menu is valid if(!this || !::IsMenu(m_hMenu)) return NULL; // Check the menu integrity if((int)GetMenuItemCount()!=(int)m_MenuItemList.GetSize()) SynchronizeMenu(); if(m_MenuItemList.GetSize()>0) return DYNAMIC_DOWNCAST(CSkinMenuItemDataTitle,m_MenuItemList[0]); return NULL; } BOOL CSkinMenu::SetMenuTitleColor(COLORREF clrTitle, COLORREF clrLeft, COLORREF clrRight) { CSkinMenuItemDataTitle* pItem = GetMemuItemDataTitle(); if(pItem) { pItem->m_clrTitle = clrTitle; pItem->m_clrLeft = clrLeft; pItem->m_clrRight = clrRight; return TRUE; } return FALSE; } BOOL CSkinMenu::SetMenuText(UINT id, CString string, UINT nFlags/*= MF_BYPOSITION*/ ) { if(MF_BYPOSITION&nFlags) { int numMenuItems = (int)m_MenuItemList.GetSize(); if(id<UINT(numMenuItems)) { // get current menu state so it doesn't change UINT nState = GetMenuState(id, MF_BYPOSITION); nState &= ~(MF_BITMAP|MF_OWNERDRAW|MF_SEPARATOR); // change the menutext CSkinMenuItemData* pItemData = m_MenuItemList[id]; pItemData->SetString(string); if(CMenu::ModifyMenu(id,MF_BYPOSITION|MF_STRING | nState, pItemData->m_nID, string)) { return ModifyMenu(id,MF_BYPOSITION | MF_OWNERDRAW,pItemData->m_nID,(LPCTSTR)pItemData); } } } else { int uiLoc; CSkinMenu* pMenu = FindMenuOption(id,uiLoc); if(NULL!=pMenu) return pMenu->SetMenuText(uiLoc,string); } return FALSE; } // courtesy of Warren Stevens void CSkinMenu::ColorBitmap(CDC* pDC, CBitmap& bmp, CSize size, COLORREF fill, COLORREF border, int hatchstyle) { // Create a memory DC CDC MemDC; MemDC.CreateCompatibleDC(pDC); bmp.CreateCompatibleBitmap(pDC, size.cx, size.cy); CPen border_pen(PS_SOLID, 1, border); CBrush fill_brush; if(hatchstyle!=-1) fill_brush.CreateHatchBrush(hatchstyle, fill); else fill_brush.CreateSolidBrush(fill); CBitmap* pOldBitmap = MemDC.SelectObject(&bmp); CPen* pOldPen = MemDC.SelectObject(&border_pen); CBrush* pOldBrush = MemDC.SelectObject(&fill_brush); MemDC.Rectangle(0,0, size.cx, size.cy); if(NULL!=pOldBrush) { MemDC.SelectObject(pOldBrush); } if(NULL!=pOldPen) { MemDC.SelectObject(pOldPen); } if(NULL!=pOldBitmap) { MemDC.SelectObject(pOldBitmap); } } BOOL CSkinMenu::OnInitMenuWnd(HWND hWnd) { CSkinMenuHook::CMenuHookData* pData = CSkinMenuHook::GetMenuHookData(hWnd); ASSERT(pData); if( pData->m_bDoSubclass) { // Flag for changing styles pData->m_dwData |= 2; SetWindowLongPtr (hWnd, GWL_STYLE, pData->m_dwStyle & (~WS_BORDER) ); if(g_Shell>=Win2000 && CSkinMenu::GetAlpha()!=255) { SetWindowLongPtr (hWnd, GWL_EXSTYLE,(pData->m_dwExStyle| WS_EX_LAYERED) & ~(WS_EX_WINDOWEDGE|WS_EX_DLGMODALFRAME)); SetLayeredWindowAttributes(hWnd, 0, CSkinMenu::GetAlpha(), LWA_ALPHA); pData->m_dwData |= 4; RedrawWindow(hWnd,NULL,NULL, RDW_ERASE | RDW_INVALIDATE | RDW_FRAME | RDW_ALLCHILDREN); } else { SetWindowLongPtr (hWnd, GWL_EXSTYLE,pData->m_dwExStyle & ~(WS_EX_WINDOWEDGE|WS_EX_DLGMODALFRAME)); } return TRUE; } return FALSE; } BOOL CSkinMenu::OnUninitMenuWnd(HWND hWnd) { CSkinMenuHook::CMenuHookData* pData = CSkinMenuHook::GetMenuHookData(hWnd); if(pData) { if(pData->m_dwData&4) { //KillTimer(hWnd,MENU_TIMER_ID); pData->m_dwData &= ~4; } HMENU hMenu = pData->m_hMenu; if(IsMenu(hMenu)) { CSkinMenu* pNewMenu = DYNAMIC_DOWNCAST(CSkinMenu,CMenu::FromHandlePermanent(hMenu)); if(pNewMenu) { // Redraw menubar on place. pNewMenu->OnUnInitPopupMenu(); } } // were windows-style changed? if(pData->m_dwData&2) { SetLastError(0); if(!(pData->m_dwData&1)) { SetWindowLongPtr (hWnd, GWL_STYLE,pData->m_dwStyle); ShowLastError(_T("Error from Menu: SetWindowLongPtr I")); } else { // Restore old Styles for special menu!! // (Menu 0x10012!!!) special VISIBLE flag must be set SetWindowLongPtr (hWnd, GWL_STYLE,pData->m_dwStyle|WS_VISIBLE); ShowLastError(_T("Error from Menu: SetWindowLongPtr I, Special")); } SetWindowLongPtr (hWnd, GWL_EXSTYLE, pData->m_dwExStyle); ShowLastError(_T("Error from Menu: SetWindowLongPtr II")); // Normaly when you change the style you shold call next function // but in this case you would lose the focus for the menu!! //SetWindowPos(hWnd,0,0,0,0,0,SWP_NOMOVE|SWP_NOSIZE|SWP_NOZORDER|SWP_FRAMECHANGED|SWP_HIDEWINDOW); } } return TRUE; } BOOL CSkinMenu::OnDrawBorder(HWND hWnd, HDC hDC, BOOL bOnlyBorder) { CSkinMenuHook::CMenuHookData* pData = (CSkinMenuHook::CMenuHookData*)SetScreenBitmap(hWnd,hDC); if( pData) { //UINT nMenuDrawMode = CSkinMenu::GetMenuDrawMode(); CRect rect; CRect client; CDC* pDC = CDC::FromHandle (hDC); // Get the size of the menu... GetWindowRect(hWnd, rect ); GetClientRect(hWnd,client); CPoint offset(0,0); ClientToScreen(hWnd,&offset); client.OffsetRect(offset-rect.TopLeft()); long winW = rect.Width(); long winH = rect.Height(); // Same Color as in DrawItem_WinXP COLORREF crMenuBar = CSkinMenu::GetMenuColor(pData->m_hMenu); COLORREF crWindow = GetSysColor(COLOR_WINDOW); COLORREF crThinBorder = MixedColor(crWindow,crMenuBar); //RGB(25,85,95); COLORREF clrBorder = RGB(25,85,95);//DarkenColor(128,crMenuBar); COLORREF colorBitmap; if (NumScreenColors() > 256) { colorBitmap = MixedColor(crMenuBar,crWindow); } else { colorBitmap = RGB(196,229,251); } // Better contrast when you have less than 256 colors if(pDC->GetNearestColor(crThinBorder)==pDC->GetNearestColor(colorBitmap)) { crThinBorder = crWindow; colorBitmap = RGB(196,229,251); } if(!IsShadowEnabled()) { if(!bOnlyBorder) { DrawFrame(pDC,CRect(CPoint(1,1),CSize(winW-6,winH-6)),client,crThinBorder); } if(bHighContrast) { pDC->Draw3dRect(CRect(CPoint(0,0),CSize(winW-4,winH-4)),GetSysColor(COLOR_BTNTEXT),GetSysColor(COLOR_BTNTEXT)); } else { pDC->Draw3dRect(CRect(CPoint(1,1),CSize(winW-6,winH-6)),crThinBorder,crThinBorder); pDC->FillSolidRect(1,2,1,winH-8,colorBitmap); pDC->Draw3dRect(CRect(CPoint(0,0),CSize(winW-4,winH-4)),clrBorder,clrBorder); DrawShade(hWnd,pDC->m_hDC,pData->m_Point); } } else { if(!bOnlyBorder) { DrawFrame(pDC,CRect(CPoint(1,1),CSize(winW-2,winH-2)),client,crThinBorder); } if(bHighContrast) { pDC->Draw3dRect(CRect(CPoint(0,0),CSize(winW-0,winH-0)),GetSysColor(COLOR_BTNTEXT ),GetSysColor(COLOR_BTNTEXT )); } else { CRgn rgn; CBrush brush; rgn.CreateRectRgn(0, 0, 0, 0); GetWindowRgn(hWnd, rgn); brush.CreateSolidBrush(clrBorder); pDC->FrameRgn(&rgn, &brush, 1, 1); brush.DeleteObject(); rgn.DeleteObject(); //pDC->Draw3dRect(CRect(CPoint(1,1),CSize(winW-2,winH-2)),crThinBorder,crThinBorder); //if(nMenuDrawMode==CSkinMenu::STYLE_XP_2003 || nMenuDrawMode==CSkinMenu::STYLE_XP_2003_NOBORDER) //{ // pDC->FillSolidRect(1,2,1,winH-4,crWindow); //} //else //{ // pDC->FillSolidRect(1,2,1,winH-4,colorBitmap); //} //pDC->Draw3dRect(CRect(CPoint(0,0),CSize(winW-0,winH-0)),clrBorder,clrBorder); } } //DrawSmalBorder(hWnd,pDC->m_hDC); return TRUE; } return FALSE; } void* CSkinMenu::SetScreenBitmap(HWND hWnd, HDC hDC) { UNREFERENCED_PARAMETER(hDC); CSkinMenuHook::CMenuHookData* pData = CSkinMenuHook::GetMenuHookData(hWnd); if(pData->m_Screen.m_hObject==NULL) { // Get the desktop hDC... HDC hDcDsk = GetWindowDC(0); CDC* pDcDsk = CDC::FromHandle(hDcDsk); CDC dc; dc.CreateCompatibleDC(pDcDsk); CRect rect; GetWindowRect(hWnd,rect); pData->m_Screen.CreateCompatibleBitmap(pDcDsk,rect.Width()+10,rect.Height()+10); CBitmap* pOldBitmap = dc.SelectObject(&pData->m_Screen); dc.BitBlt(0,0,rect.Width()+10,rect.Height()+10,pDcDsk,pData->m_Point.x,pData->m_Point.y,SRCCOPY); dc.SelectObject(pOldBitmap); // Release the desktop hDC... ReleaseDC(0,hDcDsk); } return pData; } void CSkinMenu::DrawFrame(CDC* pDC, CRect rectOuter, CRect rectInner, COLORREF crBorder) { CRect Temp; rectInner.right -= 1; // Border top Temp.SetRect(rectOuter.TopLeft(),CPoint(rectOuter.right,rectInner.top)); pDC->FillSolidRect(Temp,crBorder); // Border bottom Temp.SetRect(CPoint(rectOuter.left,rectInner.bottom),rectOuter.BottomRight()); pDC->FillSolidRect(Temp,crBorder); // Border left Temp.SetRect(rectOuter.TopLeft(),CPoint(rectInner.left,rectOuter.bottom)); pDC->FillSolidRect(Temp,crBorder); // Border right Temp.SetRect(CPoint(rectInner.right,rectOuter.top),rectOuter.BottomRight()); pDC->FillSolidRect(Temp,crBorder); } void CSkinMenu::DrawShade(HWND hWnd, HDC hDC, CPoint screen) { if(IsShadowEnabled()) return; // Get the size of the menu... CRect Rect; GetWindowRect(hWnd, Rect ); long winW = Rect.Width(); long winH = Rect.Height(); long xOrg = screen.x; long yOrg = screen.y; CSkinMenuHook::CMenuHookData* pData = CSkinMenuHook::GetMenuHookData(hWnd); CDC* pDC = CDC::FromHandle(hDC); CDC memDC; memDC.CreateCompatibleDC(pDC); CBitmap* pOldBitmap = memDC.SelectObject(&pData->m_Screen); HDC hDcDsk = memDC.m_hDC; xOrg = 0; yOrg = 0; //// Get the desktop hDC... //HDC hDcDsk = GetWindowDC(0); int X,Y; // Simulate a shadow on right edge... if (NumScreenColors() <= 256) { DWORD rgb = ::GetSysColor(COLOR_BTNSHADOW); BitBlt(hDC,winW-2,0, 2,winH,hDcDsk,xOrg+winW-2,0,SRCCOPY); BitBlt(hDC,0,winH-2,winW,2,hDcDsk,0,yOrg+winH-2,SRCCOPY); for (X=3; X<=4 ;X++) { for (Y=0; Y<4 ;Y++) { SetPixel(hDC,winW-X,Y,GetPixel(hDcDsk,xOrg+winW-X,yOrg+Y)); } for (Y=4; Y<8 ;Y++) { SetPixel(hDC,winW-X,Y,rgb); } for (Y=8; Y<=(winH-5) ;Y++) { SetPixel( hDC, winW - X, Y, rgb); } for (Y=(winH-4); Y<=(winH-3) ;Y++) { SetPixel( hDC, winW - X, Y, rgb); } } // Simulate a shadow on the bottom edge... for(Y=3; Y<=4 ;Y++) { for(X=0; X<=3 ;X++) { SetPixel(hDC,X,winH-Y, GetPixel(hDcDsk,xOrg+X,yOrg+winH-Y)); } for(X=4; X<=7 ;X++) { SetPixel( hDC, X, winH - Y, rgb); } for(X=8; X<=(winW-5) ;X++) { SetPixel( hDC, X, winH - Y, rgb); } } } else { for (X=1; X<=4 ;X++) { for (Y=0; Y<4 ;Y++) { SetPixel(hDC,winW-X,Y, GetPixel(hDcDsk,xOrg+winW-X,yOrg+Y) ); } for (Y=4; Y<8 ;Y++) { COLORREF c = GetPixel(hDcDsk, xOrg + winW - X, yOrg + Y); SetPixel(hDC,winW-X,Y,DarkenColor(2* 3 * X * (Y - 3), c)); } for (Y=8; Y<=(winH-5) ;Y++) { COLORREF c = GetPixel(hDcDsk, xOrg + winW - X, yOrg + Y); SetPixel( hDC, winW - X, Y, DarkenColor(2* 15 * X, c) ); } for (Y=(winH-4); Y<=(winH-1) ;Y++) { COLORREF c = GetPixel(hDcDsk, xOrg + winW - X, yOrg + Y); SetPixel( hDC, winW - X, Y, DarkenColor(2* 3 * X * -(Y - winH), c)); } } // Simulate a shadow on the bottom edge... for(Y=1; Y<=4 ;Y++) { for(X=0; X<=3 ;X++) { SetPixel(hDC,X,winH-Y, GetPixel(hDcDsk,xOrg+X,yOrg+winH-Y)); } for(X=4; X<=7 ;X++) { COLORREF c = GetPixel(hDcDsk, xOrg + X, yOrg + winH - Y); SetPixel( hDC, X, winH - Y, DarkenColor(2*3 * (X - 3) * Y, c)); } for(X=8; X<=(winW-5) ;X++) { COLORREF c = GetPixel(hDcDsk, xOrg + X, yOrg + winH - Y); SetPixel( hDC, X, winH - Y, DarkenColor(2* 15 * Y, c)); } } } memDC.SelectObject(pOldBitmap); //// Release the desktop hDC... //ReleaseDC(0,hDcDsk); } BOOL CSkinMenu::OnCalcFrameRect(HWND hWnd,LPRECT pRect) { GetWindowRect(hWnd,pRect); pRect->top += 2; pRect->left += 2; if(!IsShadowEnabled()) { pRect->bottom -= 7; pRect->right -= 7; } else { pRect->bottom -= 3; pRect->right -= 3; } return TRUE; } void CSkinMenu::DrawSpecial_WinXP(CDC* pDC, LPCRECT pRect, UINT nID, DWORD dwStyle) { TCHAR cSign = 0; switch(nID&0xfff0) { case SC_MINIMIZE: cSign = 48; // Min break; case SC_MAXIMIZE: cSign = 49;// Max break; case SC_CLOSE: cSign = 114;// Close break; case SC_RESTORE: cSign = 50;// Restore break; } if(cSign) { COLORREF oldColor; BOOL bBold = (dwStyle&ODS_DEFAULT) ? TRUE : FALSE; CRect rect(pRect); rect.InflateRect(0,(m_iconY-rect.Height())>>1); if( (dwStyle&ODS_GRAYED) || (dwStyle&ODS_INACTIVE)) { oldColor = pDC->SetTextColor(::GetSysColor(COLOR_GRAYTEXT)); } else if(dwStyle&ODS_SELECTED) { oldColor = pDC->SetTextColor(DarkenColorXP(GetXpHighlightColor())); rect.OffsetRect(1,1); DrawSpecialChar(pDC,rect,cSign,bBold); pDC->SetTextColor(::GetSysColor(COLOR_MENUTEXT)); rect.OffsetRect(-2,-2); } else { oldColor = pDC->SetTextColor(::GetSysColor(COLOR_MENUTEXT)); } DrawSpecialChar(pDC,rect,cSign,bBold); pDC->SetTextColor(oldColor); } } CRect CSkinMenu::GetLastActiveMenuRect() { return m_LastActiveMenuRect; } void CSkinMenu::DrawSpecialCharStyle(CDC* pDC, LPCRECT pRect, TCHAR Sign, DWORD dwStyle) { COLORREF oldColor; if( (dwStyle&ODS_GRAYED) || (dwStyle&ODS_INACTIVE)) { oldColor = pDC->SetTextColor(::GetSysColor(COLOR_GRAYTEXT)); } else { oldColor = pDC->SetTextColor(::GetSysColor(COLOR_MENUTEXT)); } DrawSpecialChar(pDC,pRect,Sign,(dwStyle&ODS_DEFAULT) ? TRUE : FALSE); pDC->SetTextColor(oldColor); } void CSkinMenu::DrawSpecialChar(CDC* pDC, LPCRECT pRect, TCHAR Sign, BOOL bBold) { // 48 Min // 49 Max // 50 Restore // 98 Checkmark // 105 Bullet // 114 Close CFont MyFont; LOGFONT logfont; CRect rect(pRect); rect.DeflateRect(2,2); logfont.lfHeight = -rect.Height(); logfont.lfWidth = 0; logfont.lfEscapement = 0; logfont.lfOrientation = 0; logfont.lfWeight = (bBold) ? FW_BOLD:FW_NORMAL; logfont.lfItalic = FALSE; logfont.lfUnderline = FALSE; logfont.lfStrikeOut = FALSE; logfont.lfCharSet = DEFAULT_CHARSET; logfont.lfOutPrecision = OUT_DEFAULT_PRECIS; logfont.lfClipPrecision = CLIP_DEFAULT_PRECIS; logfont.lfQuality = DEFAULT_QUALITY; logfont.lfPitchAndFamily = DEFAULT_PITCH; _tcscpy_s(logfont.lfFaceName,ARRAY_SIZE(logfont.lfFaceName),_T("Marlett")); MyFont.CreateFontIndirect (&logfont); CFont* pOldFont = pDC->SelectObject (&MyFont); int OldMode = pDC->SetBkMode(TRANSPARENT); pDC->DrawText (&Sign,1,rect,DT_CENTER|DT_SINGLELINE); pDC->SetBkMode(OldMode); pDC->SelectObject(pOldFont); } ////////////////////////////////////////////////////////////////////// // Construction/Destruction ////////////////////////////////////////////////////////////////////// const TCHAR _OldMenuProc[] = _T("OldMenuProc"); //HMODULE CSkinMenuHook::m_hThemeLibrary = NULL; HHOOK CSkinMenuHook::HookOldMenuCbtFilter = NULL; HMENU CSkinMenuHook::m_hLastMenu = NULL; DWORD CSkinMenuHook::m_dwMsgPos = 0; DWORD CSkinMenuHook::m_bSubclassFlag = 0; #ifdef _TRACE_MENU_LOGFILE HANDLE CSkinMenuHook::m_hLogFile = INVALID_HANDLE_VALUE; #endif //_TRACE_MENU_LOGFILE //CTypedPtrList<CPtrList, CSkinMenuTheme*>* CSkinMenuHook::m_pRegisteredThemesList = NULL; CTypedPtrMap<CMapPtrToPtr,HWND,CSkinMenuHook::CMenuHookData*> CSkinMenuHook::m_MenuHookData; #ifndef SM_REMOTESESSION #define SM_REMOTESESSION 0x1000 #endif CSkinMenuHook::CSkinMenuHook() { HIGHCONTRAST highcontrast = {0}; highcontrast.cbSize = sizeof(highcontrast); if(SystemParametersInfo(SPI_GETHIGHCONTRAST,sizeof(highcontrast),&highcontrast,0) ) { bHighContrast = ((highcontrast.dwFlags & HCF_HIGHCONTRASTON)!=0); } if (HookOldMenuCbtFilter == NULL) { HookOldMenuCbtFilter = ::SetWindowsHookEx(WH_CALLWNDPROC, SkinMenuHook, NULL, ::GetCurrentThreadId()); if (HookOldMenuCbtFilter == NULL) { ShowLastError(_T("Error from Menu: SetWindowsHookEx")); AfxThrowMemoryException(); } } } CSkinMenuHook::~CSkinMenuHook() { if (HookOldMenuCbtFilter != NULL) { if(!::UnhookWindowsHookEx(HookOldMenuCbtFilter)) { ShowLastError(_T("Error from Menu: UnhookWindowsHookEx")); } HookOldMenuCbtFilter = NULL; } //pIsThemeActive = NULL; // Cleanup for shared menu icons if(CSkinMenu::m_pSharedMenuIcons) { delete CSkinMenu::m_pSharedMenuIcons; CSkinMenu::m_pSharedMenuIcons = NULL; } } CSkinMenuHook::CMenuHookData* CSkinMenuHook::GetMenuHookData(HWND hWnd) { CMenuHookData* pData=NULL; if(m_MenuHookData.Lookup(hWnd,pData)) { return pData; } return NULL; } void CSkinMenuHook::UnsubClassMenu(HWND hWnd) { AFX_MANAGE_STATE(AfxGetModuleState()); WNDPROC oldWndProc = (WNDPROC)::GetProp(hWnd, _OldMenuProc); ASSERT(oldWndProc != NULL); SetLastError(0); if(!SetWindowLongPtr(hWnd, GWLP_WNDPROC, (INT_PTR)oldWndProc)) { ShowLastError(_T("Error from Menu: SetWindowLongPtr III")); } RemoveProp(hWnd, _OldMenuProc); GlobalDeleteAtom(GlobalFindAtom(_OldMenuProc)); // now Clean up HMENU hMenu = NULL; // Restore old Styles for special menu!! (Menu 0x10012!!!) CMenuHookData* pData = GetMenuHookData(hWnd); if(pData) { hMenu = pData->m_hMenu; CSkinMenu::OnUninitMenuWnd(hWnd); m_MenuHookData.RemoveKey(hWnd); delete pData; } } LRESULT CALLBACK CSkinMenuHook::SubClassMenu(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { AFX_MANAGE_STATE(AfxGetModuleState()); WNDPROC oldWndProc = (WNDPROC)::GetProp(hWnd, _OldMenuProc); LRESULT result = NULL; BOOL bCallDefault = TRUE; CMenuHookData* pData = GetMenuHookData(hWnd); if(NULL == pData) { ASSERT(oldWndProc!=NULL); return ::CallWindowProc(oldWndProc, hWnd, uMsg, wParam, lParam); } ASSERT(pData); switch(uMsg) { case WM_NCPAINT: ASSERT(pData); if(pData->m_bDoSubclass) { if(!pData->m_bDrawBorder) { if(pData->m_hRgn!=(HRGN)wParam) { if(pData->m_hRgn!=(HRGN)1) { DeleteObject(pData->m_hRgn); pData->m_hRgn=(HRGN)1; } if(wParam!=1) { CRgn dest; dest.CreateRectRgn( 0, 0, 1, 1); dest.CopyRgn(CRgn::FromHandle((HRGN)wParam)); pData->m_hRgn = (HRGN)dest.Detach(); } } } if(pData->m_dwData & 8) { // do not call default!!! bCallDefault=FALSE; } if(pData->m_bDrawBorder) { HDC hDC = GetWindowDC (hWnd); if(CSkinMenu::OnDrawBorder(hWnd,hDC)) { CRect rect; if(CSkinMenu::OnCalcFrameRect(hWnd,rect)) { CRgn rgn; rect.InflateRect(-1,-1); rgn.CreateRectRgnIndirect(rect); // do we need a combination of the regions? //if(wParam!=1) //{ // rgn.CombineRgn(&rgn,CRgn::FromHandle((HRGN)wParam),RGN_AND); //} ASSERT(oldWndProc); bCallDefault=FALSE; result = CallWindowProc(oldWndProc, hWnd, uMsg, (WPARAM)rgn.m_hObject, lParam); //result = CallWindowProc(oldWndProc, hWnd, uMsg, wParam, lParam); // Redraw the border and shade CSkinMenu::OnDrawBorder(hWnd,hDC,true); } } ReleaseDC(hWnd,hDC); } if(bCallDefault) { // Save the background HDC hDC = GetWindowDC (hWnd); CSkinMenu::SetScreenBitmap(hWnd,hDC); ReleaseDC(hWnd,hDC); } } break; case WM_PRINT: if(pData && pData->m_bDoSubclass) { // Mark for WM_PRINT pData->m_dwData |= 8; // pData->m_bDrawBorder = FALSE; // We need to create a bitmap for drawing // We can't clipp or make a offset to the DC because NT2000 (blue-screen!!) CRect rect; GetWindowRect(hWnd, rect); CDC dc; CBitmap bitmap; CDC* pDC = CDC::FromHandle((HDC)wParam); dc.CreateCompatibleDC(pDC); bitmap.CreateCompatibleBitmap(pDC, rect.Width(), rect.Height()); CBitmap* pOldBitmap = dc.SelectObject(&bitmap); // new // dc.FillSolidRect(0,0,rect.Width(), rect.Height(),CSkinMenu::GetMenuBarColor(pData->m_hMenu)); CSkinMenu::OnDrawBorder(hWnd,dc.m_hDC); CRect rectClient; if(CSkinMenu::OnCalcFrameRect(hWnd,rectClient)) { // might as well clip to the same rectangle CRect clipRect = rectClient; clipRect.OffsetRect(rectClient.TopLeft()-rect.TopLeft()); clipRect.InflateRect(-1,-1); dc.IntersectClipRect(clipRect); result = CallWindowProc(oldWndProc, hWnd, uMsg, (WPARAM)dc.m_hDC, lParam&~PRF_CLIENT); pDC->BitBlt(0,0, rect.Width(), rect.Height(), &dc,0,0, SRCCOPY); GetClientRect(hWnd,clipRect); SelectClipRgn(dc.m_hDC,NULL); dc.IntersectClipRect(clipRect); SendMessage(hWnd,WM_ERASEBKGND,(WPARAM)dc.m_hDC,0); SendMessage(hWnd,WM_PRINTCLIENT,(WPARAM)dc.m_hDC,lParam); CPoint wndOffset(0,0); ClientToScreen(hWnd,&wndOffset); wndOffset -= rect.TopLeft(); pDC->BitBlt(wndOffset.x,wndOffset.y, clipRect.Width()-1, clipRect.Height(), &dc, 0, 0, SRCCOPY); //pDC->BitBlt(wndOffset.x,wndOffset.y, clipRect.Width(), clipRect.Height(), &dc, 0, 0, SRCCOPY); } // dc.SelectObject(pOldBitmap); bCallDefault=FALSE; // Clear for WM_PRINT pData->m_dwData &= ~8; } break; //case WM_ERASEBKGND: // ASSERT(pData); // if(pData->m_bDoSubclass) // { // if(CSkinMenu::m_pActMenuDrawing->DoDrawBorder()) // { // if(!(pData->m_dwData&8) && !pData->m_bDrawBorder ) // { // pData->m_bDrawBorder = true; // //SendMessage(hWnd,WM_NCPAINT,(WPARAM)pData->m_hRgn,0); // SendMessage(hWnd,WM_NCPAINT,(WPARAM)1,0); // } // } // if(CSkinMenu::m_pActMenuDrawing->OnEraseBkgnd(hWnd,(HDC)wParam)) // { // bCallDefault=FALSE; // result = TRUE; // } // } // break; case WM_WINDOWPOSCHANGED: case WM_WINDOWPOSCHANGING: { ASSERT(pData); LPWINDOWPOS pPos = (LPWINDOWPOS)lParam; if(uMsg==WM_WINDOWPOSCHANGING) { if(!IsShadowEnabled()) { pPos->cx +=2; pPos->cy +=2; } else { pPos->cx -=2; pPos->cy -=2; } pPos->y -=1; } if(!(pPos->flags&SWP_NOMOVE) ) { if(pData->m_Point==CPoint(0,0)) { pData->m_Point = CPoint(pPos->x,pPos->y); } else if(pData->m_Point!=CPoint(pPos->x,pPos->y)) { /* CRect rect(0,0,0,0); if(!GetWindowRect(hWnd,rect)) { TRACE(_T("Error get rect\n")); } #ifdef _TRACE_MENU_ DWORD dwPos =GetMessagePos(); TRACE(_T("Rect pos (%ld/%ld), dimensions [%ld,%ld], Delta(%ld/%ld),MPos %lx\n"), pData->m_Point.x,pData->m_Point.y,rect.Width(),rect.Height(), pData->m_Point.x-pPos->x,pData->m_Point.y-pPos->y,dwPos); #endif */ if(!(pPos->flags&SWP_NOSIZE)) { UnsubClassMenu(hWnd); } else { pData->m_Point=CPoint(pPos->x,pPos->y); pData->m_Screen.DeleteObject(); } } } } break; case WM_KEYDOWN: if(wParam==VK_ESCAPE) { if(pData) { pData->m_dwData |= 4; } } m_dwMsgPos = GetMessagePos(); break; case WM_NCCALCSIZE: if(pData->m_bDoSubclass) { NCCALCSIZE_PARAMS* pCalc = (NCCALCSIZE_PARAMS*)lParam; int cx=0,cy=0; if(!IsShadowEnabled()) { cx = 5; cy = 6; } else { cx = 1; cy = 2; } pCalc->rgrc->top += 2; pCalc->rgrc->left += 2; pCalc->rgrc->bottom -= cy; pCalc->rgrc->right -= cx; } break; case WM_SHOWWINDOW: // Hide the window ? Test for 98 and 2000 if(wParam==NULL) { // Special handling for NT 2000 and WND 0x10012. UnsubClassMenu(hWnd); } break; case WM_NCDESTROY: { UnsubClassMenu (hWnd); break; } case WM_SIZE: { CRect rcWindow; CRgn rgn; GetWindowRect(hWnd, &rcWindow); rcWindow.OffsetRect(-rcWindow.TopLeft()); rgn.CreateRoundRectRgn(rcWindow.left, rcWindow.top, rcWindow.right+1, rcWindow.bottom+1, MENU_ROUND_CX, MENU_ROUND_CY); SetWindowRgn(hWnd, rgn, TRUE); break; } } if( bCallDefault ) { ASSERT(oldWndProc != NULL); // call original wndproc for default handling result = CallWindowProc(oldWndProc, hWnd, uMsg, wParam, lParam); } return result; } BOOL CSkinMenuHook::CheckSubclassing(HWND hWnd, BOOL bSpecialWnd) { TCHAR Name[32]; int Count = GetClassName (hWnd,Name,ARRAY_SIZE(Name)); // Check for the menu-class if(Count!=6 || _tcscmp(Name,_T("#32768"))!=0) { // does not match to menuclass return FALSE; } BOOL bDoNewSubclass = FALSE; CMenuHookData* pData=GetMenuHookData(hWnd); // check if we have allready some data if(pData==NULL) { // a way for get the menu-handle not documented m_hLastMenu = (HMENU)SendMessage(hWnd,MN_GETHMENU,0,0); if (m_hLastMenu==NULL) return FALSE; CMenu *pMenu = CMenu::FromHandlePermanent(m_hLastMenu); // now we support only new menu if( !DYNAMIC_DOWNCAST(CSkinMenu,pMenu) ) return FALSE; WNDPROC oldWndProc; // subclass the window with the proc which does gray backgrounds oldWndProc = (WNDPROC)GetWindowLongPtr(hWnd, GWLP_WNDPROC); if (oldWndProc != NULL && GetProp(hWnd, _OldMenuProc) == NULL) { ASSERT(oldWndProc!=SubClassMenu); if(!SetProp(hWnd, _OldMenuProc, oldWndProc)) { ShowLastError(_T("Error from Menu: SetProp")); } if ((WNDPROC)GetProp(hWnd, _OldMenuProc) == oldWndProc) { GlobalAddAtom(_OldMenuProc); CMenuHookData* pData=GetMenuHookData(hWnd); ASSERT(pData==NULL); if(pData==NULL) { pData = new CMenuHookData(hWnd,bSpecialWnd); m_MenuHookData.SetAt (hWnd,pData); SetLastError(0); if(!SetWindowLongPtr(hWnd, GWLP_WNDPROC,(INT_PTR)SubClassMenu)) { ShowLastError(_T("Error from Menu: SetWindowLongPtr IV")); } bDoNewSubclass = TRUE; // CSkinMenu::OnInitMenuWnd(hWnd); } } else { ASSERT(0); } } } // Menu was set also assign it to this menu. if(m_hLastMenu) { CMenuHookData* pData = GetMenuHookData(hWnd); if(pData) { // Safe actual menu pData->SetMenu(m_hLastMenu); // Reset for the next menu m_hLastMenu = NULL; CSkinMenu::OnInitMenuWnd(hWnd); } } return bDoNewSubclass; } ///////////////////////////////////////////////////////////////////////////// // CSkinMenuTempHandler class used to add NewMenu to system dialog class CSkinMenuTempHandler : public CObject { CSkinMenu m_SystemNewMenu; WNDPROC m_oldWndProc; HWND m_hWnd; public: CSkinMenuTempHandler(HWND hWnd) { m_hWnd = hWnd; VERIFY(SetProp(hWnd,_T("CSkinMenuTempHandler"),this)); // Subclass the dialog control. m_oldWndProc = (WNDPROC)(LONG_PTR)SetWindowLongPtr(hWnd, GWLP_WNDPROC,(INT_PTR)TempSubclass); } ~CSkinMenuTempHandler() { SetWindowLongPtr(m_hWnd, GWLP_WNDPROC,(INT_PTR)m_oldWndProc); VERIFY(RemoveProp(m_hWnd,_T("CSkinMenuTempHandler"))); } LRESULT Default(UINT uMsg, WPARAM wParam, LPARAM lParam ) { // call original wndproc for default handling return CallWindowProc(m_oldWndProc, m_hWnd, uMsg, wParam, lParam); } LRESULT OnCmd(UINT uMsg, WPARAM wParam, LPARAM lParam) { MSG msg = {m_hWnd,uMsg,wParam,lParam,0,0,0}; switch(uMsg) { case WM_DRAWITEM: { if(m_SystemNewMenu.m_hMenu) { DRAWITEMSTRUCT* lpDrawItemStruct = (DRAWITEMSTRUCT*)lParam; if (lpDrawItemStruct->CtlType == ODT_MENU) { CMenu* pMenu = CMenu::FromHandlePermanent((HMENU)lpDrawItemStruct->hwndItem); if (DYNAMIC_DOWNCAST(CSkinMenu,pMenu)) { pMenu->DrawItem(lpDrawItemStruct); return true; // eat it } } } return Default(uMsg, wParam, lParam); } case WM_MEASUREITEM: if(CSkinMenu::OnMeasureItem(&msg)) { return TRUE; } break; case WM_MENUCHAR: { CMenu* pMenu = CMenu::FromHandle(HMENU((UINT)lParam)); LRESULT lresult; if( DYNAMIC_DOWNCAST(CSkinMenu,pMenu) ) lresult=CSkinMenu::FindKeyboardShortcut(LOWORD(wParam), HIWORD(wParam),pMenu ); else lresult=Default(uMsg, wParam, lParam); return lresult; } break; case WM_INITMENUPOPUP: { CMenu* pMenu = CMenu::FromHandle(HMENU((UINT)wParam)); LRESULT result = Default(uMsg, wParam, lParam); CSkinMenu::OnInitMenuPopup(m_hWnd, pMenu, LOWORD(lParam), HIWORD(lParam)); return result; } case WM_INITDIALOG: if(CSkinMenuHook::m_bSubclassFlag & SKIN_MENU_DIALOG_SYSTEM_MENU) { LRESULT bRetval = Default(uMsg, wParam, lParam); VERIFY(m_SystemNewMenu.m_hMenu==0); HMENU hMenu = ::GetSystemMenu(m_hWnd,FALSE); if(IsMenu(hMenu)) { CMenu* pMenu = CMenu::FromHandlePermanent(hMenu); // Only attach to CSkinMenu once if (DYNAMIC_DOWNCAST(CSkinMenu,pMenu)==NULL ) { m_SystemNewMenu.Attach(hMenu); } } return bRetval; } break; case WM_DESTROY: LRESULT result = Default(uMsg, wParam, lParam); delete this; return result; } return Default(uMsg, wParam, lParam); } // Subclass procedure static LRESULT APIENTRY TempSubclass(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { AFX_MANAGE_STATE(AfxGetModuleState()); CSkinMenuTempHandler* pTemp = (CSkinMenuTempHandler*)GetProp(hwnd,_T("CSkinMenuTempHandler")); ASSERT(pTemp); return pTemp->OnCmd(uMsg, wParam, lParam); } }; LRESULT CALLBACK CSkinMenuHook::SkinMenuHook(int code, WPARAM wParam, LPARAM lParam) { AFX_MANAGE_STATE(AfxGetModuleState()); CWPSTRUCT* pTemp = (CWPSTRUCT*)lParam; if(code == HC_ACTION ) { HWND hWnd = pTemp->hwnd; // Normal and special handling for menu 0x10012 if(pTemp->message==WM_CREATE || pTemp->message==0x01E2) { if(!CheckSubclassing(hWnd,pTemp->message==0x01E2)) { if( (m_bSubclassFlag & SKIN_MENU_DIALOG_SUBCLASS) && pTemp->message==WM_CREATE) { TCHAR Name[20]; int Count = GetClassName (hWnd,Name,ARRAY_SIZE(Name)); // Check for the Dialog-class if(Count==6 && _tcscmp(Name,_T("#32770"))==0 ) { // Only first dialog // m_bSubclassFlag &= ~SKIN_MENU_DIALOG_SUBCLASS; // Freed by WM_DESTROY new CSkinMenuTempHandler(hWnd); } } } } } return CallNextHookEx(HookOldMenuCbtFilter, code,wParam, lParam); } //TCHAR szShadeWindowClass[] = _T("ShadeWindow"); // //typedef struct //{ // CRect parentRect; // HWND hParent; // BOOL bSideShade; //}SShadeInfo; // //void DrawWindowShade(HDC hDC, CRect rect, COLORREF blendColor) //{ // if (NumScreenColors() <= 256) // { // DWORD rgb = ::GetSysColor(COLOR_BTNSHADOW); // COLORREF oldColor = ::SetBkColor(hDC, rgb); // ::ExtTextOut(hDC, 0, 0, ETO_OPAQUE, &rect, NULL, 0, NULL); // ::SetBkColor(hDC, oldColor); // } // else // { // COLORREF ref; // int width = rect.Width(); // int height = rect.Height(); // int X,Y; // // if(width<height) // { // for (X=0; X<=4 ;X++) // { // for (Y=0; Y<=4 ;Y++) // { // // Simulate a shadow on the left edge... // ref = GetAlphaBlendColor(blendColor,GetPixel(hDC,X,Y),255-(4-X)*Y*10); // SetPixel(hDC,X,Y,ref); // } // for (;Y<height;Y++) // { // // Simulate a shadow on the left... // ref = GetAlphaBlendColor(blendColor,GetPixel(hDC,X,Y),240-(4-X)*40); // SetPixel(hDC,X,Y,ref); // } // } // } // else // { // for(Y=0; Y<=4 ;Y++) // { // // Simulate a shadow on the bottom edge... // for(X=0; X<=4 ;X++) // { // ref = GetAlphaBlendColor(blendColor,GetPixel(hDC,X,Y),255-(4-Y)*X*10); // SetPixel(hDC,X,Y,ref); // } // // Simulate a shadow on the bottom... // for(;X<=(width-5);X++) // { // ref = GetAlphaBlendColor(blendColor,GetPixel(hDC,X,Y),240-(4-Y)*40); // SetPixel(hDC,X,Y,ref); // } // // Simulate a shadow on the bottom edge... // for(;X<width;X++) // { // ref = GetAlphaBlendColor(blendColor,GetPixel(hDC,X,Y),255-((width-1-X)*(4-Y))*10); // SetPixel(hDC,X,Y,ref); // } // } // } // } //}